Friday, December 30, 2011

Check element existance in Geb

In Geb, if you need to check if some element does exists on page or not the best looking way to do it is method isPresent(), so it can be called like:

!notNeededLink.present
otherLink.present

Of course if you plan to check non-existing elements like this they need to be defined as not required and with wait - false. For example:

notNeededLink(to: SomePage, required:false, wait: false) {$('a', text:'Some')}

Tuesday, December 20, 2011

Too many idle database connections with Tomcat

I recently had problem when there were too many open database connections in Tomcat. Everything was right, but number is far more then is defined in Tomcat resources.
After some investigation, I have found that problem was that datasources were defined in wrong place - conf/context.xml, and when they are defined there, they are picked for every Web application that is defined in this Tomcat instance (including management and utility), therefore you will have all your connections multiplied by number of applications you have.
Fortunately, it is easy to fix by defining resources under conf/Catalina/localhost/ROOT.xml (ROOT if application is defined under root, otherwise, name of your application), in which case, resources will be provided only for specified application.

Tuesday, December 6, 2011

Passing upstream parameters to downstream builds in Jenkins

Jenkins has cool Pipeline plugin, which helps to create build pipelines, that for example, can organize and visualize deployment process. Plugin is very cool and looks great, but lacks few basic features, like passing generated parameters or variables from upstream builds to downstream.
For example, I wanted to pass SVN revision number into downstream builds.
Fortunately it is easy to do it with little hacking. Here is what I did.
  1. Add Groovy plugin.
  2. Add new build step Execute system Groovy script, now it is possible to hook into Jenkins internals.
  3. Then just add Groovy script there:
import hudson.model.*
def thr = Thread.currentThread()
def build = thr?.executable
build.addAction(new ParametersAction(new StringParameterValue('SVN_UPSTREAM', build.getEnvVars()['SVN_REVISION'])))


What this script does it just creates new parameter and adds SVN_REVISION from environment variables there. And pipeline can pass parameters with this mechanism to downstream builds (all of them).
Easy!

Monday, November 28, 2011

Encoding problems in Grails

If there are problems with charsets while submitting forms in Tomcat, and headers for responses/requests looks correct, you can try to fix it by adding URIEncoding="UTF-8" into your server.xml. This fixed things nicely to me. Read more about it at http://wiki.apache.org/tomcat/FAQ/CharacterEncoding.

Thursday, November 24, 2011

MySQL dump without locking tables

If you just do MySQL dump without any parameters, it locks tables and consumes a lot of memory. If you want to avoid it and you have InnoDB, best way to do it is to add single-transaction (run in single transaction) and q (dump one row at once) properties, for example like:

mysqldump -q --single-transaction -u login -ppassword db > dump.sql


Monday, November 14, 2011

Time difference with DST

If you need to calculate time difference that include Daylight Saving Time in Groovy, it is super simple with groovy.time.TimeCategory:

TimeDuration hours = TimeCategory.minus(end.time, start.time)

Monday, October 24, 2011

CSS word-wrap in table

When

word-wrap: break-word;

is applied to table cell, it does seems to wrap anything.
If you want to make it work, just add

table-layout:fixed;

to table definition and it works nicely.

Friday, October 21, 2011

HTTPS without certificate validation check

By default Java validates certificates when you do HTTPS queries. If it is not needed (for test environments, for example), it is possible to disable it (even it is much more complicated then it should be). Just add this code somewhere during initialization (this is groovy, so sorry some formatting):


  import javax.net.ssl.*
  import java.security.cert.*

  javax.net.ssl.TrustManager tm = new javax.net.ssl.X509TrustManager() {
    public boolean isClientTrusted(X509Certificate[] chain) { return true; }
    public boolean isHostTrusted(X509Certificate[] chain) { return true; }
    public boolean isServerTrusted(X509Certificate[] chain) { return true; }
    public X509Certificate[] getAcceptedIssuers() { return null; }
    public void checkClientTrusted(X509Certificate[] chain, String s){  }
    public void checkServerTrusted(X509Certificate[] chain, String s) {  }
  }
  HostnameVerifier hv = new HostnameVerifier() {
        public boolean verify(String urlHostName, SSLSession session) { return true; }
  }
  TrustManager[] trustAllCerts = new TrustManager[1];
  trustAllCerts[0] = tm;
  SSLContext sc = SSLContext.getInstance("SSL");
  sc.init(null, trustAllCerts, new java.security.SecureRandom());
  HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
  HttpsURLConnection.setDefaultHostnameVerifier(hv);



Wednesday, October 19, 2011

JUnit report formatting in Grails

Sometimes it is needed to add some additional information to JUnit report. For example, if you want to add screenshots and so on. It can be easily done in Grails.
First, you need to modify scripts/_Events.groovy and redefine reporting template folder.

eventAllTestsStart = {
  junitReportStyleDir = "src/templates/reports/"
}

Then create src/templates/reports folder and just add junit-frames.xsl and junit-noframes.xsl from lib folder under Grails home.

Now Grails will use these files to format test results.

Renaming Session cookie in JBoss and Tomcat

JSESSIONID is standard defined name, but in some cases it is needed to rename it. In JBoss and Tomcat it is very easy, you can do it by defining system property org.apache.catalina.JSESSIONID in JAVA_OPTS, for example:

-Dorg.apache.catalina.JSESSIONID=PC1SESSIONID

Friday, October 14, 2011

Grails with custom Lucene configuration for each environment

Sometimes it is needed to deal with non-grails configuration in Grails project, and usually there is problem if you need to use different configuration for different environment.
For example, recently I had to configure Lucene with compass.cfg.xml. And in production it is using MySQL dialect, and in test environment H2.
So in this case you can hook into Grails and adjust configuration for specific environment via events in scripts/_Events.groovy. For example, in my case I was just deleting custom configuration and using RAM store in test environment, like:

eventPackagingEnd = { msg -> 
  def file = new File("${grailsSettings.resourcesDir}/compass.cfg.xml")
  file.delete()
}

Of course, in different situations you can use different approach and for example, replace it with another file and so on.

InvalidClassException: GrailsUser and plugin upgrade

Recently when I tried to deploy new version of application on live server without downtime, I got error:

2011-10-14 11:02:52,058 [Tribes-Task-Receiver-4] ERROR org.apache.catalina.ha.session.DeltaManager- Manager [localhost#]: Unable to receive message through TCP channel
java.io.InvalidClassException: org.codehaus.groovy.grails.plugins.springsecurity.GrailsUser; local class incompatible: stream classdesc serialVersionUID = -3114204362518930756, local class serialVersionUID =
        at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:579)
        at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1600)
        at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1513)
        at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1600)
        at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1513)
        at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1749)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1346)
        at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1963)
        at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1887)
        at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1770)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1346)
        at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1963)

Basically, error is trivial, just some Spring security classes are not versioned and cluster can't synchronize users data. Fortunately, as I have found out, no hacking is needed and it can be easily fixed by upgrading spring-security-core plugin to the latest version.

To upgrade to latest version, just uninstall plugin and install it again, like:

grails uninstall-plugin spring-security-core
grails install-plugin spring-security-core

Wednesday, October 12, 2011

Using properties from Grails script

If you have custom Grails script and need to access property file from it, I found that easiest way to do it is to use Ant. There is complete example how to access file and to use variables:
ant.property(file:'user.properties')
ant.scp(file:'target/app.war', todir:"${ant.project.properties.login}:${ant.project.properties.password}@server:/home/tomcat/", trust:true)

Sudo without password prompt

Remote scripts often do something that requires root rights, common approach is to use sudo. But by default it interactively prompts for password, which is not easy thing if you execute commands automatically. Fortunately, it can be easily configured not to do it. All that is needed to do is to update /etc/sudoers, and change something like this:
testuser    ALL=(ALL) ALL
to something like this:
testuser    ALL=(ALL) NOPASSWD: ALL

Quartz error: Parameter index out of range

Recently, I had to configure Quartz in cluster. Most common approach to do it is to use database, there is a lot of tutorials and examples, but whatever I was using I bumped into this exception:
2011-10-12 10:44:44,861 [main] ERROR context.GrailsContextLoader  - Error executing bootstraps: org.quartz.JobPersistenceException: Couldn't store trigger 'mySimpleTrigger' for 'TestUpdaterJob' job:Parameter index out of range (2 > number of parameters, which is 1). [See nested exception: java.sql.SQLException: Parameter index out of range (2 > number of parameters, which is 1).]
org.codehaus.groovy.runtime.InvokerInvocationException: org.quartz.JobPersistenceException: Couldn't store trigger 'mySimpleTrigger' for 'TestUpdaterJob' job:Parameter index out of range (2 > number of parameters, which is 1). [See nested exception: java.sql.SQLException: Parameter index out of range (2 > number of parameters, which is 1).]
    at org.grails.tomcat.TomcatServer.start(TomcatServer.groovy:212)
    at grails.web.container.EmbeddableServer$start.call(Unknown Source)
    at _GrailsRun_groovy$_run_closure5_closure12.doCall(_GrailsRun_groovy:158)
    at _GrailsRun_groovy$_run_closure5_closure12.doCall(_GrailsRun_groovy)
    at _GrailsSettings_groovy$_run_closure10.doCall(_GrailsSettings_groovy:280)
    at _GrailsSettings_groovy$_run_closure10.call(_GrailsSettings_groovy)
    at _GrailsRun_groovy$_run_closure5.doCall(_GrailsRun_groovy:149)
    at _GrailsRun_groovy$_run_closure5.call(_GrailsRun_groovy)
    at _GrailsRun_groovy.runInline(_GrailsRun_groovy:116)
    at _GrailsRun_groovy.this$4$runInline(_GrailsRun_groovy)
    at _GrailsRun_groovy$_run_closure1.doCall(_GrailsRun_groovy:59)
    at RunApp$_run_closure1.doCall(RunApp.groovy:33)
    at gant.Gant$_dispatch_closure5.doCall(Gant.groovy:381)
    at gant.Gant$_dispatch_closure7.doCall(Gant.groovy:415)
    at gant.Gant$_dispatch_closure7.doCall(Gant.groovy)
    at gant.Gant.withBuildListeners(Gant.groovy:427)
    at gant.Gant.this$2$withBuildListeners(Gant.groovy)
    at gant.Gant$this$2$withBuildListeners.callCurrent(Unknown Source)
    at gant.Gant.dispatch(Gant.groovy:415)
    at gant.Gant.this$2$dispatch(Gant.groovy)
    at gant.Gant.invokeMethod(Gant.groovy)
    at gant.Gant.executeTargets(Gant.groovy:590)
    at gant.Gant.executeTargets(Gant.groovy:589)
Caused by: org.quartz.JobPersistenceException: Couldn't store trigger 'mySimpleTrigger' for 'TestUpdaterJob' job:Parameter index out of range (2 > number of parameters, which is 1). [See nested exception: java.sql.SQLException: Parameter index out of range (2 > number of parameters, which is 1).]
    at org.quartz.impl.jdbcjobstore.JobStoreSupport.storeTrigger(JobStoreSupport.java:1245)
    at org.quartz.impl.jdbcjobstore.JobStoreSupport$5.execute(JobStoreSupport.java:1151)
    at org.quartz.impl.jdbcjobstore.JobStoreSupport$40.execute(JobStoreSupport.java:3691)
    at org.quartz.impl.jdbcjobstore.JobStoreCMT.executeInLock(JobStoreCMT.java:242)
    at org.quartz.impl.jdbcjobstore.JobStoreSupport.executeInLock(JobStoreSupport.java:3687)
    at org.quartz.impl.jdbcjobstore.JobStoreSupport.storeTrigger(JobStoreSupport.java:1147)
    at org.quartz.core.QuartzScheduler.scheduleJob(QuartzScheduler.java:849)
    at org.quartz.impl.StdScheduler.scheduleJob(StdScheduler.java:254)
    at org.quartz.Scheduler$scheduleJob.call(Unknown Source)
    at QuartzGrailsPlugin$_closure5_closure24.doCall(QuartzGrailsPlugin.groovy:229)
    at QuartzGrailsPlugin$_closure5.doCall(QuartzGrailsPlugin.groovy:224)
    at QuartzGrailsPlugin.invokeMethod(QuartzGrailsPlugin.groovy)
    at QuartzGrailsPlugin$_closure3_closure21.doCall(QuartzGrailsPlugin.groovy:175)
    at QuartzGrailsPlugin$_closure3.doCall(QuartzGrailsPlugin.groovy:173)
    ... 23 more
Caused by: java.sql.SQLException: Parameter index out of range (2 > number of parameters, which is 1).
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1073)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:987)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:982)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:927)
    at com.mysql.jdbc.PreparedStatement.checkBounds(PreparedStatement.java:3729)
    at com.mysql.jdbc.PreparedStatement.setInternal(PreparedStatement.java:3713)
    at com.mysql.jdbc.PreparedStatement.setString(PreparedStatement.java:4553)
    at com.mysql.jdbc.BlobFromLocator.length(BlobFromLocator.java:333)
    at org.quartz.impl.jdbcjobstore.StdJDBCDelegate.getObjectFromBlob(StdJDBCDelegate.java:3463)
    at org.quartz.impl.jdbcjobstore.StdJDBCDelegate.selectJobDetail(StdJDBCDelegate.java:904)
    at org.quartz.impl.jdbcjobstore.JobStoreSupport.storeTrigger(JobStoreSupport.java:1201)
    ... 36 more

Google does not have a lot of information about it and I had to dig Quartz sources to investigate it, but finally I found that problem is emulateLocators=true on my database URL. I use this parameter for Lucene clustering so it seems there is conflict between them, so it is not possible to use common data source. Otherwise, it fixes this exception easily.

Wednesday, October 5, 2011

Calling stored procedure from JdbcTemplate

I am using JdbcTemplate to make database queries, like:
List<Map<String,Object>> rows = jdbcTemplate.queryForList("select * from rows");
Recently I had to replace SQL selects with stored procedures, but after doing so, I had exception:
java.sql.SQLException: The SQL statement must not contain a procedure call or parameter markers.
        at net.sourceforge.jtds.jdbc.JtdsStatement.executeQuery(JtdsStatement.java:1297)
        at com.mchange.v2.c3p0.impl.NewProxyStatement.executeQuery(NewProxyStatement.java:35)
        at org.springframework.jdbc.core.JdbcTemplate$1QueryStatementCallback.doInStatement(JdbcTemplate.java:440)
        at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:395)
        at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:455)
        at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:463)
        at org.springframework.jdbc.core.JdbcTemplate.queryForList(JdbcTemplate.java:494)
As I found out finally, when queryForList is called without parameters it cann't call stored procedures, so to do it you just need to add empty parameter list:
List<Map<String,Object>> tables = jdbcTemplate.queryForList("{call getRows() }", new Object[] {});

Tuesday, September 20, 2011

Running ant task in maven

Sometimes you have some task that you just need to execute: without attaching to build phase, or any process - just run. Unfortunately maven is not very flexible about it. Fortunately, it is still possible. To do it, you need use antrun plugin with custom profile. For example, like this:

<profiles>
  <profile>
     <id>deploy</id>
     <build>
        <plugins>
          <plugin>
            <artifactId>maven-antrun-plugin</artifactId>
            <version>1.3</version>
            <configuration>
              <tasks>
                <property file="user.properties" prefix="user"/>
                <scp file="target/target.war" todir="${user.login}:${user.password}@${user.server}:/home/user/" trust="true"/>
                <sshexec host="${user.server}" username="${user.login}" password="${user.password}" command="sudo ./redeploy.sh" trust="true" />
              </tasks>
            </configuration>
            <dependencies>
                <dependency>
                    <groupId>org.apache.ant</groupId>
                    <artifactId>ant-jsch</artifactId>
                    <version>1.7.1</version>
                </dependency>
                <dependency>
                    <groupId>com.jcraft</groupId>
                    <artifactId>jsch</artifactId>
                    <version>0.1.42</version>
                </dependency>
            </dependencies>
          </plugin>
        </plugins>
     </build>
  </profile>
...

</profiles>

Later, you can run this script like:


mvn antrun:run -Pdeploy

Of course you can have different scripts in several profiles.

This approach even has advantages over having separate Ant's build.xml - you don't need to have separate Ant installation, or for instance, with example above, you don't need to download jsch plugin separately - it is all done by Maven.

Friday, September 16, 2011

Java web application monitoring tool

I was looking for production monitoring tool recently. I didn't have any specific requirements, just to have some understanding about load and bottlenecks. Finally, after some googling I found one very interesting option JavaMelody.

This tool takes risky, but very interesting approach, proxies JDBC calls, loads as web filter, advisor for Spring, etc. Additionally, it watches usual VM stuff, like JMX. As result it has a lot of very detailed and deep statistics, like sql queries time, page load times, and so on. Also it provides a lot of graphics and tables, to watch, generally looks nice and advanced. Of course with this approach it looks quite dangerous, but seems like this is already mature tool and I would like to try to use it in my projects.

Also, it has very nice and simple integration with Grails. Just install Grails-melody plugin, and you have your statistics under URL <hostname:port/app-ctx>/monitoring. This is regular application URL, so you can easily configure access rights and login in your application.

Thursday, September 1, 2011

Hibernate "not-found" in Grails

Often when you delete object from db instead of just marking it as deleted, there is nasty exception that this object is referenced by someone else.
2011-09-01 15:18:38,953 [http-8080-1] ERROR errors.GrailsExceptionResolver  - Exception occurred when processing request: [GET] xxx
Stacktrace follows:
org.codehaus.groovy.grails.web.pages.exceptions.GroovyPagesException: Error processing GroovyPageView: Error executing tag <g:form>: Error executing tag <sec:ifAllGranted>: Error evaluating expression [xxx.yyy?.id] on line [70]: No row with the given identifier exists: [xxx#21244] at xxx.gsp:71 at xxx.gsp:102
    at java.lang.Thread.run(Thread.java:662)
Caused by: org.codehaus.groovy.grails.web.taglib.exceptions.GrailsTagException: Error executing tag <g:form>: Error executing tag <sec:ifAllGranted>: Error evaluating expression [xxx.yyy?.id] on line [70]: No row with the given identifier exists: [yyy#21244] at xxx.gsp:71 at xxx.gsp:102
    ... 1 more
Caused by: org.codehaus.groovy.grails.web.taglib.exceptions.GrailsTagException: Error executing tag <sec:ifAllGranted>: Error evaluating expression [xxx.yyy?.id] on line [70]: No row with the given identifier exists: [xxx#21244] at xxx.gsp:71
    ... 4 more
Caused by: org.codehaus.groovy.grails.web.pages.exceptions.GroovyPagesException: Error evaluating expression [xxx.yyy?.id] on line [70]: No row with the given identifier exists: [xxx#21244]
    at grails.plugins.springsecurity.SecurityTagLib$_closure1.doCall(SecurityTagLib.groovy:60)
    ... 7 more
Caused by: org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [xxx#21244]
    ... 10 more
In Hibernate there is nice not-found="ignore" for such cases. In Grails/GORM there is similar option which is not documented for some reason. Just add ignoreNotFound to domain objects mapping section and that is it. For example:
class Log {
  User user

  static mapping = {
    user ignoreNotFound : true 
  }

}

Tuesday, August 2, 2011

"Slash n" in db migrations scripts in Grails

If it is needed to print \n from migration script, it is needed to write 4 slashes before n (1, 2 or 3 will just print new line symbol), so it should look something like:

  changeSet(author: "user", id: "1") {
    insert(tableName: "table") {
      column (name:'column', value:'''aaaa\\\\nbbbb''')
    }
  }


will result in value being -

aaaa\nbbbb

Monday, August 1, 2011

Cannot delete parent object in GORM

Sometimes, when trying to delete parent object in GORM, even when there is children cascade:'all-delete-orphan' there is exception:

com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (`db`.`domain`, CONSTRAINT `FKB8FB823DBF953235` FOREIGN KEY (`domain_id`) REFERENCES `user` (`id`))
    at com.mysql.jdbc.Util.handleNewInstance(Util.java:409)
    at com.mysql.jdbc.Util.getInstance(Util.java:384)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1041)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3566)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3498)
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1959)
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2113)
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2568)
    at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2113)
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2409)
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2327)
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2312)
    at org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105)
    at org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105)

It is possible to solve this issue, by explicitly clearing all children from parent object before delete.

    domain.children.clear()


After that it successfully deletes domain object.

Sunday, July 31, 2011

NoSuchElementException after click() in Selenium 2

Sometimes in Selenium 2 after clicking on some element, it does not execute actual click (but does not throws error that element is not found), cann't find element from next page and therefore throws this exception:

Unable to locate element: {"method":"class name","selector":"alert"} For documentation on this error, please visit: http://seleniumhq.org/exceptions/no_such_element.html Build info: version: '2.2.0', revision: '13073', time: '2011-07-26 00:54:48' System info: os.name: 'Windows 7', os.arch: 'amd64', os.version: '6.1', java.version: '1.6.0_24' Driver info: driver.version: RemoteWebDriver

org.openqa.selenium.NoSuchElementException: Unable to locate element: {"method":"class name","selector":"alert"}
For documentation on this error, please visit: http://seleniumhq.org/exceptions/no_such_element.html
Build info: version: '2.2.0', revision: '13073', time: '2011-07-26 00:54:48'
System info: os.name: 'Windows 7', os.arch: 'amd64', os.version: '6.1', java.version: '1.6.0_24'
Driver info: driver.version: RemoteWebDriver
    at org.openqa.selenium.remote.ErrorHandler.createThrowable(ErrorHandler.java:131)
    at org.openqa.selenium.remote.ErrorHandler.throwIfResponseFailed(ErrorHandler.java:105)
    at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:405)
    at org.openqa.selenium.remote.RemoteWebDriver.findElement(RemoteWebDriver.java:193)
    at org.openqa.selenium.remote.RemoteWebDriver.findElementByClassName(RemoteWebDriver.java:250)
    at org.openqa.selenium.By$ByClassName.findElement(By.java:349)
    at org.openqa.selenium.remote.RemoteWebDriver.findElement(RemoteWebDriver.java:185)
    at org.openqa.selenium.WebDriver$findElement.call(Unknown Source)
...
Caused by: org.openqa.selenium.remote.ErrorHandler$UnknownServerException: Unable to locate element: {"method":"class name","selector":"alert"}
Build info: version: '2.2.0', revision: '13073', time: '2011-07-26 00:54:48'
System info: os.name: 'Windows 7', os.arch: 'amd64', os.version: '6.1', java.version: '1.6.0_24'
Driver info: driver.version: unknown

First, you should check that there is no element with same selector and it does not tries to click some div. Second, I found that sometimes if there is floating div, especial over your links or buttons, it cann't properly click it. In latter case, best solution for form buttons is to use submit, instead of click, like:
driver.findElement(By.id("update")).submit();
Another thing that helps - especially with links, is to remove overflowing div (closing it - depends on your application logic) and waiting for second, like:
Thread.sleep(1000);

Tuesday, July 26, 2011

How to ignore failed database migrations

When using Grails database migration plugin, failing migrations is sign of some problem - usually some syntax error. But in some cases it is not needed and it is ok to ignore them. For example, I faced this problem while testing application which created db in memory from Hibernate entities. Some particular migrations, like ones dealing with existing records or legacy columns, were failing with no meaning.
Fortunately, there is easy way to ignore some migrations. Just add failOnError:'false' to change set definition and it will report exception in logs, but will continue with loading. There is example:

  changeSet(author: "user", id: "96", failOnError:'false') {
    update(tableName: "table") {
      column(name: "column", valueBoolean: false)
      where ('column is null')
    }
  }


This is good that it is specified per change set, as only these dealing with particular columns will be able to fail, it will be still strict with others. Only way it would be better, if there would be global property, so it would be still strict in production, but more forgiving in test environment.

Unable to locate element in Selenium 2

There is new version of Selenium, which is very good and easy to use, unfortunately there is too little documentation yet. After I started to use it, one of the first issues I found is this:

org.openqa.selenium.NoSuchElementException: Unable to locate element: {"method":"link text","selector":"Home"}
For documentation on this error, please visit: http://seleniumhq.org/exceptions/no_such_element.html
Build info: version: '2.2.0', revision: '13073', time: '2011-07-26 00:54:48'
System info: os.name: 'Windows 7', os.arch: 'amd64', os.version: '6.1', java.version: '1.6.0_24'
Driver info: driver.version: RemoteWebDriver
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
        at org.openqa.selenium.remote.ErrorHandler.createThrowable(ErrorHandler.java:131)
        at org.openqa.selenium.remote.ErrorHandler.throwIfResponseFailed(ErrorHandler.java:105)
        at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:405)
        at org.openqa.selenium.remote.RemoteWebDriver.findElement(RemoteWebDriver.java:193)
        at org.openqa.selenium.remote.RemoteWebDriver.findElementByLinkText(RemoteWebDriver.java:218)
        at org.openqa.selenium.By$ByLinkText.findElement(By.java:223)
        at org.openqa.selenium.remote.RemoteWebDriver.findElement(RemoteWebDriver.java:185)
        at org.openqa.selenium.WebDriver$findElement.call(Unknown Source)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
        at selenium.run(selenium.groovy:14)
        at groovy.lang.GroovyShell.runScriptOrMainOrTestOrRunnable(GroovyShell.java:266)
        at groovy.lang.GroovyShell.run(GroovyShell.java:229)
        at groovy.lang.GroovyShell.run(GroovyShell.java:159)
        at groovy.ui.GroovyMain.processOnce(GroovyMain.java:514)
        at groovy.ui.GroovyMain.run(GroovyMain.java:329)
        at groovy.ui.GroovyMain.process(GroovyMain.java:315)
        at groovy.ui.GroovyMain.processArgs(GroovyMain.java:112)
        at groovy.ui.GroovyMain.main(GroovyMain.java:93)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.codehaus.groovy.tools.GroovyStarter.rootLoader(GroovyStarter.java:108)
        at org.codehaus.groovy.tools.GroovyStarter.main(GroovyStarter.java:130)
Caused by: org.openqa.selenium.remote.ErrorHandler$UnknownServerException: Unable to locate element: {"method":"link text","selector":"Home"}
Build info: version: '2.2.0', revision: '13073', time: '2011-07-26 00:54:48'
System info: os.name: 'Windows 7', os.arch: 'amd64', os.version: '6.1', java.version: '1.6.0_24'
Driver info: driver.version: unknown

even when element is present on the page. After some googling I found easy solution to this issue:

    driver = new FirefoxDriver();
    driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); 

This is default period which Selenium will try to wait for element to appear on the page, before throwing error, and this works perfectly for me.


Saturday, July 23, 2011

MissingMethodException when running test with baseUrl in Grails

Running functional test with baseUrl option can end with exception:

Error executing script TestApp: groovy.lang.MissingMethodException: No signature of method: static java.lang.System.setProperty() is applicable for argument types: (java.lang.String, java.lang.Boolean)
Possible solutions: setProperty(java.lang.String, java.lang.String), getProperty(java.lang.String), getProperty(java.lang.String, java.lang.String), hasProperty(java.lang.String), getProperties(), getP
groovy.lang.MissingMethodException: No signature of method: static java.lang.System.setProperty() is applicable for argument types: (java.lang.String, java.lang.Boolean) values: [grails.testing.functio
Possible solutions: setProperty(java.lang.String, java.lang.String), getProperty(java.lang.String), getProperty(java.lang.String, java.lang.String), hasProperty(java.lang.String), getProperties(), getP
        at gant.Gant$_dispatch_closure5.doCall(Gant.groovy:391)
        at gant.Gant$_dispatch_closure7.doCall(Gant.groovy:415)
        at gant.Gant$_dispatch_closure7.doCall(Gant.groovy)
        at gant.Gant.withBuildListeners(Gant.groovy:427)
        at gant.Gant.this$2$withBuildListeners(Gant.groovy)
        at gant.Gant$this$2$withBuildListeners.callCurrent(Unknown Source)
        at gant.Gant.dispatch(Gant.groovy:415)
        at gant.Gant.this$2$dispatch(Gant.groovy)
        at gant.Gant.invokeMethod(Gant.groovy)
        at gant.Gant.executeTargets(Gant.groovy:590)
        at gant.Gant.executeTargets(Gant.groovy:589)
Caused by: groovy.lang.MissingMethodException: No signature of method: static java.lang.System.setProperty() is applicable for argument types: (java.lang.String, java.lang.Boolean) values: [grails.test
Possible solutions: setProperty(java.lang.String, java.lang.String), getProperty(java.lang.String), getProperty(java.lang.String, java.lang.String), hasProperty(java.lang.String), getProperties(), getP
        at _GrailsTest_groovy$_run_closure11.doCall(_GrailsTest_groovy:366)
        at _GrailsTest_groovy$_run_closure11.doCall(_GrailsTest_groovy)
        at _GrailsTest_groovy$_run_closure1_closure21.doCall(_GrailsTest_groovy:184)
        at _GrailsTest_groovy$_run_closure1.doCall(_GrailsTest_groovy:174)
        at TestApp$_run_closure1.doCall(TestApp.groovy:82)
        at gant.Gant$_dispatch_closure5.doCall(Gant.groovy:381)
        ... 10 more

This can be easily worked around by running tests in interactive mode. Just run:

grails interactive

and you can execute your tests from there like:

test test-app functional: MyTests -baseUrl="http://..."

Apart from that it works, this gives also additional benefits like: you can debug with single attachment from IDE (remember to use grails-debug); also you can run grails application before executing tests which allows to use in-memory db with functional testing.

Monday, July 18, 2011

BLOB and TEXT type for fields in GORM

If you need long type for your fields with GORM automatic table creation, you just need to specify appropriate constraint for that field, like:
description(nullable:true, maxSize:1000000)

Sunday, July 17, 2011

c3p0 Connection reset error

By default c3p0 does not pings or destroys opened connections, so it will not know if database closes old connection until someone will try to use it. It leads to bad errors like:

Caused by: java.sql.SQLException: I/O Error: Connection reset
        at net.sourceforge.jtds.jdbc.TdsCore.executeSQL(TdsCore.java:1053)
        at net.sourceforge.jtds.jdbc.TdsCore.submitSQL(TdsCore.java:899)
        at net.sourceforge.jtds.jdbc.ConnectionJDBC2.setAutoCommit(ConnectionJDBC2.java:2259)
        at com.mchange.v2.c3p0.impl.NewProxyConnection.setAutoCommit(NewProxyConnection.java:881)
        at org.hibernate.transaction.JDBCTransaction.begin(JDBCTransaction.java:91)


Fortunately, this can be easily fixed as c3p0 has all necessary facilities for pinging and maintaining connections. There are several options, you can read about them in c3p0 docs, I found easiest for me asynchronously pinging waiting connections every few minutes with trivial select. For example, this will specify ping connection every 3 minute in MS SQL:

         <Set name="idleConnectionTestPeriod">180</Set>
         <Set name="preferredTestQuery">select 1</Set>


Saturday, July 16, 2011

Spring security in grails - roles and permissions

There is nice plugin for using Spring security in Grails - it integrates nicely in application, can be heavily customized and is easy to use. I didn't had extensive experience with Spring security before, but all security frameworks that I used, have something that represents roles and permissions. Role is group of permissions, and permissions are either defined only for groups or can be assigned to users explicitly. From first glance at Spring security there is only concept for roles (or as they called in plugin - Authorities). It confused me very much and created impression of very basic framework.

It took some time to figure out, that on the contrary - Spring security is very powerful and flexible also in this sense. Basically, all it cares is what authorities you return in your users getAuthorities() method. So you can generate whatever hierarchy of permissions you want, possibly adjust it by the time or the day, or simply generate it on the fly.

Friday, July 15, 2011

Rich text component validation

Rich Text Components return HTML code, and if you are going to show it on your pages there is problem that some bad person can submit malicious HTML to your server and if you will display it "as is", this code can do something bad. So you have to check somehow that code that is submitted is generate by your component, or at least is safe. Latter is called HTML sanitization.
Simple pattern matching is too trivial, as malicious code can be hidden behind some strange unicode symbols or so (you can check how tricky it is at http://ha.ckers.org/xss.html). Basically, it usually requires parsing HTML and detecting, what can be used and what can't. Fortunately, there is already nice HTML parser built into JDK. It is intended to be used in Swing, but is abstract enough to be used for validation too. What you need to do is to extend javax.swing.text.html.parser.Parser, like:

import javax.swing.text.html.parser.*
import static javax.swing.text.html.HTML.Tag.*
import static javax.swing.text.html.HTML.Attribute.*

class RteParser extends Parser {
  boolean hasErrors = false
    
  public RteParser() {
    super(DTD.getDTD('html'));
  }
  
  void validateTag(tag) {
    ...
  }
  
  void handleStartTag(TagElement tag) {
    validateTag(tag)
    this.flushAttributes()
  }
  
  void handleEndTag(TagElement tag) {
    validateTag(tag)
    this.flushAttributes()
  }
  
  void handleEmptyTag(TagElement tag) {
    validateTag(tag)
    this.flushAttributes()
  }

  public static boolean validate(String value) {
    RteParser parser = new RteParser()
    StringReader reader = new StringReader("<html>${value}</html>")
    parser.parse(reader)
    return parser.isValid()
  }
  
  public boolean isValid() {
    return !hasErrors
  }

}



All validation can be done by calling static validate method.
All magic is done in validateTag. This method is specific, this is place where you check all tags and attributes against some black list or validation patterns.

Wednesday, July 6, 2011

Whole object validation with Grails

There is nice field validation framework in Grails (based on Spring) with a lot of documentation.
However recently I needed to implement whole object validation (I have some rules across different fields). It is easily supported by Grails, but is not that well documented. All you need to do is to is to implement method beforeValidate in your domain object, like:

def beforeValidate() {
  if (somethingbad()) {
    errors.addError("fieldname", "something bad happened")
  }
}


All errors that you have you should put into errors object, which is instance of
org.springframework.validation.BeanPropertyBindingResult and you can add errors as org.springframework.validation.ObjectError instances.

Monday, July 4, 2011

Handling HTML changes via DOMSubtreeModified

Recently, I needed to handle changes in DOJO rich text editor. It supports all traditional events, but my problem was that I needed to handle also copy/pastes and especially mouse copy/pastes (right button context menu), as I have found, it does not counts as mouse events. After some investigation I have found nice, but for some reason not so popular event DOMSubtreeModified.
So I am able to handle all changes by subscribing to changes like:
rte.addEventListener("DOMSubtreeModified", function(){
   ...
}

One issue with this approach is that it is not supported by all browsers and is depricated by W3, but I need this feature for controlled environment.

Saturday, June 25, 2011

Executable WAR and jetty:run

After creating executable WAR I have noticed that when I run application with jetty:run, there is conflict between jetty libs from maven plugin and application dependencies:

2011-06-26 00:54:14.067:INFO::jetty-8.0.0.M2
2011-06-26 00:54:15.779:WARN::Failed startup of context JettyWebAppContext@5a347448@5a347448/myexecutable,file:/
java.lang.IllegalArgumentException: Object is not of type class org.eclipse.jetty.webapp.WebAppContext
        at org.eclipse.jetty.xml.XmlConfiguration.configure(XmlConfiguration.java:204)
        at org.eclipse.jetty.plus.webapp.EnvConfiguration.configure(EnvConfiguration.java:98)
        at org.eclipse.jetty.webapp.WebAppContext.configure(WebAppContext.java:473)
        at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1174)
        at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:598)
        at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:496)
        at org.mortbay.jetty.plugin.JettyWebAppContext.doStart(JettyWebAppContext.java:175)
        at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:55)
        at org.eclipse.jetty.server.handler.HandlerCollection.doStart(HandlerCollection.java:226)
        at org.eclipse.jetty.server.handler.ContextHandlerCollection.doStart(ContextHandlerCollection.java:164)
        at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:55)
        at org.eclipse.jetty.server.handler.HandlerCollection.doStart(HandlerCollection.java:226)
        at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:55)
        at org.eclipse.jetty.server.handler.HandlerWrapper.doStart(HandlerWrapper.java:93)
        at org.eclipse.jetty.server.Server.doStart(Server.java:244)
        at org.mortbay.jetty.plugin.JettyServer.doStart(JettyServer.java:67)
        at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:55)
        at org.mortbay.jetty.plugin.AbstractJettyMojo.startJetty(AbstractJettyMojo.java:447)
        at org.mortbay.jetty.plugin.AbstractJettyMojo.execute(AbstractJettyMojo.java:387)
        at org.mortbay.jetty.plugin.JettyRunMojo.execute(JettyRunMojo.java:555)
        at org.apache.maven.plugin.DefaultPluginManager.executeMojo(DefaultPluginManager.java:490)
        at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(DefaultLifecycleExecutor.java:694)
        at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeStandaloneGoal(DefaultLifecycleExecutor.java:569)
        at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoal(DefaultLifecycleExecutor.java:539)
        at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalAndHandleFailures(DefaultLifecycleExecutor.java:387)
        at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeTaskSegments(DefaultLifecycleExecutor.java:348)
        at org.apache.maven.lifecycle.DefaultLifecycleExecutor.execute(DefaultLifecycleExecutor.java:180)

I have found that this problem can be quickly solved by using maven profiles.
All that is needed to do is to define new profile, and move all dependencies there:

<profiles>
  <profile>
      <id>myexecutablewar</id>
      <activation>
        <property>
          <name>myexecutablewar</name>
          <value>true</value>
        </property>
      </activation>
    <dependencies>

        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-server</artifactId>
            <version>8.0.0.M2</version>
        </dependency>

        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-jndi</artifactId>
            <version>8.0.0.M2</version>
        </dependency>

        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-plus</artifactId>
            <version>8.0.0.M2</version>
        </dependency>

        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-start</artifactId>
            <version>8.0.0.M2</version>
        </dependency>

        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-webapp</artifactId>
            <version>8.0.0.M2</version>
        </dependency>

        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-servlet</artifactId>
            <version>8.0.0.M2</version>
        </dependency>

        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-util</artifactId>
            <version>8.0.0.M2</version>
        </dependency>

        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-jmx</artifactId>
            <version>8.0.0.M2</version>
        </dependency>

        <dependency>
            <groupId>org.mortbay.jetty</groupId>
            <artifactId>jsp-2.1-glassfish</artifactId>
            <version>2.1.v20100127</version>
        </dependency>
    </dependencies>

  </profile>
</profiles>

Now, when you simply run

mvn jetty:run

it runs without using dependencies, but when you run

mvn install -Dmyexecutablewar=true
it uses dependencies and creates executable package.

Executable WAR

Recently I created very small and lightweight web application. It supposed to be using web sockets, so I decided to use Jetty as application server, but instead of using it like container, I decided to save on project and configuration folders and scripts and deploy it as executable WAR.
It was surprisingly easy to do. Basically, only thing that is needed is maven with Shade plugin. This plugin allows to pack all dependencies together in single JAR. Also it allows to modify manifest, and comes with simple examples.
So, all you need to do is to add jetty dependencies to pom.xml, for example:

        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-server</artifactId>
            <version>8.0.0.M2</version>
        </dependency>

        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-jndi</artifactId>
            <version>8.0.0.M2</version>
        </dependency>

        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-plus</artifactId>
            <version>8.0.0.M2</version>
        </dependency>

        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-start</artifactId>
            <version>8.0.0.M2</version>
        </dependency>

        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-webapp</artifactId>
            <version>8.0.0.M2</version>
        </dependency>

        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-servlet</artifactId>
            <version>8.0.0.M2</version>
        </dependency>

        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-util</artifactId>
            <version>8.0.0.M2</version>
        </dependency>

        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-jmx</artifactId>
            <version>8.0.0.M2</version>
        </dependency>

        <dependency>
            <groupId>org.mortbay.jetty</groupId>
            <artifactId>jsp-2.1-glassfish</artifactId>
            <version>2.1.v20100127</version>
        </dependency>

And Shade plugin configuration:

            <plugin>
              <groupId>org.apache.maven.plugins</groupId>
              <artifactId>maven-shade-plugin</artifactId>
              <version>1.4</version>
            <executions>
              <execution>
                <phase>package</phase>
                <goals>
                  <goal>shade</goal>
                </goals>
                <configuration>
                  <artifactSet>
                    <includes>
                      <include>org.eclipse.jetty:*</include>
                      <include>org.mortbay.jetty:*</include>
                      <include>net.sourceforge.jtds:jtds</include>
                      <include>org.slf4j:*</include>
                      <include>log4j:*</include>
                      <include>c3p0:c3p0</include>
                    </includes>
                  </artifactSet>
                  <transformers>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                      <manifestEntries>
                        <Main-Class>org.eclipse.jetty.start.Main</Main-Class>
                        <Build-Number>123</Build-Number>
                      </manifestEntries>
                    </transformer>
                  </transformers>
                </configuration>
              </execution>
            </executions>
            </plugin>


And as output you should get nice, executable WAR web application, that is ready to be launched as easy as:

java -jar myexecutable.war jetty.xml

Of course it is good idea to externalize logging or jetty configuration in separate jetty.xml file, so you can change it without creating new deployment.
It can be as simple as:

<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
<Configure id="FileServer" class="org.eclipse.jetty.server.Server">

    <Call name="addConnector">
      <Arg>
          <New class="org.eclipse.jetty.server.nio.SelectChannelConnector">
            <Set name="port">8080</Set>
            <Set name="Host">localhost</Set>
          </New>
      </Arg>
    </Call>

    <Set name="handler">
      <New class="org.eclipse.jetty.server.handler.HandlerList">
        <Set name="handlers">
          <Array type="org.eclipse.jetty.server.Handler">
            <Item>
              <New class="org.eclipse.jetty.webapp.WebAppContext">
                <Set name="contextPath">/myexecutable</Set>
                <Set name="war">myexecutable.war</Set>
              </New>
            </Item>
          </Array>
        </Set>
      </New>
    </Set>

  <New id="onewalletDS" class="org.eclipse.jetty.plus.jndi.Resource">
    <Arg>myDS</Arg>
    <Arg>
      <New class="com.mchange.v2.c3p0.ComboPooledDataSource">
         <Set name="driverClass">net.sourceforge.jtds.jdbcx.JtdsDataSource</Set>
         <Set name="user">user</Set>
         <Set name="password">password</Set>
         <Set name="jdbcUrl">jdbc:jtds:sqlserver://localhost/myds</Set>
     </New>
    </Arg>
  </New>

</Configure>

Friday, April 1, 2011

Playing music file from HTML page

This is first time I need this in many years, but finally this day has come: I need to play MP3 file from web page.
Looks like the easiest way to do is by using embed tag, so when I need it is needed to play it, I just call from javascript:
$('#sound_element').html("<embed src='scripts/"+file+".mp3' hidden='true' autostart='true' loop='false'>");
Of course I need to have this div somewhere on the page:
<div id="sound_element"></div>
And it does the magic. I found that it plays flawlessly in Chrome, but for Firefox it asks for Quicktime plugin. But I need it for managed environment, so it is not a big deal.
Finally, I can add some tunes to my blog! ;)

Skip XML declaration in JAXB

By default JAXB outputs XML declaration when you marshal your objects:
For example, this:

JAXBContext context = JAXBContext.newInstance(Command.class, Message.class...);
Marshaller marshaller = context.createMarshaller();
marshaller.marshal(command, writer);
will output this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<message channel="test"/>


If you don't need to use XML declaration in your JAXB output, it is easy to skip it by setting property "jaxb.fragment" to true. So, this:
JAXBContext context = JAXBContext.newInstance(Command.class, Message.class...);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty("jaxb.fragment", Boolean.TRUE);
marshaller.marshal(command, writer);
will output only this:
<message channel="test"/>


Friday, March 18, 2011

Get text from java mail

If you don't want to dig javamail structures and mime types, there is easy way to extract text from Message object described in javamail official docs (I wonder why they didn't put it directly into specification).

Friday, February 25, 2011

Spring Integration namespaces in resources.groovy

Spring Integration relies heavily on namespaces usage, so if you need to use it, this can be easily defined in Grails Spring DSL:


beans = {
  xmlns integration:"http://www.springframework.org/schema/integration"
  xmlns mail:"http://www.springframework.org/schema/integration/mail"
  xmlns jms:"http://www.springframework.org/schema/integration/jms"

}

After that you can define your channels like:

  integration.channel(id:'inboundEmailChannel')

Thursday, February 24, 2011

Processing incoming emails with Spring Integration

Recently, I had a task to automatically process emails that come to specified address. Trivial solution is to create some periodic task with Quartz or Timer and pull new emails and process them. I googled if there is ready lib to do this and found that this can be done with Spring; or more specifically with Spring Integration. I heard about this project, but didn't payed a lot of attention to it. Main idea behind it is - this is small local ESB, so basically if you need to act on some incoming event or send some outgoing event to some system, this is nice place to look at. Another good thing is that it provides easy and out-of-the-box ready interface to many different systems, which is exactly what I was looking for email processing.
So with Spring Integration, reading email is just few beans definition (in Grails Spring DSL):


  integration.channel(id:'inboundEmailChannel')

  mail.'inbound-channel-adapter'(id:"imapAdapter",
      'store-uri':"imaps://${CH.config.logging.imap.credentials}@imap.gmail.com/INBOX",
      'java-mail-properties':['mail.imap.socketFactory.class':'javax.net.ssl.SSLSocketFactory',
            'mail.imap.socketFactory.fallback':false,
             'mail.store.protocol':'imaps', 'mail.debug':false],
      channel:"inboundEmailChannel",
      'should-delete-messages':true,
      'should-mark-messages-as-read':true,
      'auto-startup':true) {
          integration.poller('max-messages-per-poll':"1", 'fixed-rate':"5000")
   }

   integration.'service-activator'( 'input-channel':"inboundEmailChannel",
                ref:"emailService", method:"inboundEmail")


So, with this, when you have incoming email, it will call inboundEmail method of emailService.

Tuesday, January 11, 2011

Configuration properties in resources.groovy

In Grails there is support for property placeholders in resources.xml, but for resources.groovy you should do it manually. Fortunately, it is quite easy, here is example:

import org.codehaus.groovy.grails.commons.ConfigurationHolder as CH

beans = {
  integration.channel(id:'channel', host:'imaps://user:${CH.config.imap.password}@imap.gmail.com/INBOX')
}