2008年12月17日水曜日

[Grails]Integration Terracotta(Java VM Clustering) with Grails manually

Steps to Integrate the Terracotta(Java VM Clustering) with Grails manually without using the Terracotta plugin.
  • References
  • Steps
    • Install Java development kit
    • Install latest grails
    • Install latest terracotta
    • Create terracotta's config file as follows
      (Following is a example configuration, please refer to the terracotta documentation about the detail of the config file)
      Following configuration is clustered the util.cache.Cache.cacheMap object, and set the named-lock for all the methods.
      <?xml version="1.0" encoding="UTF-8"?>
      <tc:tc-config xmlns:tc="http://www.terracotta.org/config"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.terracotta.org/schema/terracotta-4.xsd">

      <servers>
      <server name="server1" host="localhost">
      <data>%(user.home)/terracotta/server-data</data>
      <logs>%(user.home)/terracotta/server-logs</logs>
      <dso>
      <client-reconnect-window>10</client-reconnect-window>
      <persistence>
      <mode>temporary-swap-only</mode>
      </persistence>
      <garbage-collection>
      <enabled>true</enabled>
      <verbose>false</verbose>
      <interval>180</interval>
      </garbage-collection>
      </dso>
      <jmx-port>9520</jmx-port>
      <l2-group-port>9530</l2-group-port>
      </server>
      </servers>

      <clients>
      <logs>%(user.home)/terracotta/client-logs</logs>
      </clients>

      <application>
      <dso>
      <roots>
      <root>
      <field-name>util.cache.Cache.cacheMap</field-name>
      </root>
      </roots>

      <instrumented-classes>
      <include>
      <class-expression>util.cache.Cache</class-expression>
      </include>
      </instrumented-classes>

      <locks>
      <named-lock>
      <lock-name>CacheMapWriteLock</lock-name>
      <lock-level>write</lock-level>
      <method-expression>* util.cache.Cache.clear(..)</method-expression>
      </named-lock>

      <named-lock>
      <lock-name>CacheMapWriteLock</lock-name>
      <lock-level>concurrent</lock-level>
      <method-expression>* util.cache.Cache.set(..)</method-expression>
      </named-lock>

      <named-lock>
      <lock-name>CacheMapWriteLock</lock-name>
      <lock-level>concurrent</lock-level>
      <method-expression>* util.cache.Cache.remove(..)</method-expression>
      </named-lock>

      <named-lock>
      <lock-name>CacheMapReadLock</lock-name>
      <lock-level>read</lock-level>
      <method-expression>* util.cache.Cache.get(..)</method-expression>
      </named-lock>

      <named-lock>
      <lock-name>CacheMapReadLock</lock-name>
      <lock-level>read</lock-level>
      <method-expression>* util.cache.Cache.contain(..)</method-expression>
      </named-lock>
      </locks>
      </dso>
      </application>
      </tc:tc-config>
    • Start the terracotta server
      ${TC_INSTALL_DIR}/bin/start-tc-server.sh -f (Set path to the terracotta config) -n (Set server name in terracotta config file)
    • Set the environment variables
      export JAVA_HOME=(Set JDK's home directory)
      export GRAILS_HOME=(Set Grails home directory)
      export JAVA_OPTS="(Set java option parameters if you need)"
      export TC_INSTALL_DIR=(Set Teraccotta's home directory)
      export JAVACMD="${TC_INSTALL_DIR}/bin/dso-java.sh"
      export JAVA_OPTS="$JAVA_OPTS -Dtc.config=(Set path to the terracotta config file)"
    • Start Grails web server
      grails -Dserver.port=(Set Port Number) run-app dev
      (When executing this command, jetty is started after grails command run the terracotta client and read the configration file because the JAVACMD environment variable is set to the terracotta shell script file)
    • Integration terracotta with the tomcat
      Please refer to the terracotta documentation for more detail.
      http://www.terracotta.org/web/display/orgsite/Tomcat+Integration

      Following is a sample tomcat startup script.
      JAVA_HOME="(top directory name installed the jdk)"
      JAVA_OPTS="-server -Xms256m -Xmx512m -Xss256k"
      TOMCAT_HOME="(top directory name installed the tomcat)"
      PATH="$PATH:$JAVA_HOME/bin:$ANT_HOME/bin:$TOMCAT_HOME/bin"

      TC_INSTALL_DIR="(directory name installed the terracotta)"
      TC_CONFIG_PATH="(full path name of the terracotta configuration file.)"
      . $TC_INSTALL_DIR/bin/dso-env.sh -q
      export JAVA_OPTS="$TC_JAVA_OPTS $JAVA_OPTS"
      sh ${TOMCAT_HOME}/bin/catalina.sh start
    • Integration terracotta with jetty
      Please refer to the terracotta documentation.
      http://www.terracotta.org/web/display/orgsite/Jetty+Integration

2008年12月15日月曜日

[Linux]yum process hangs and stacks without erroring out

  • References
    Yum hangs(http://www.windley.com/archives/2007/04/yum_hangs.shtml)
  • Description
    yum process sometimes hangs and stacks without erroring out. No error messages are outputted. I get the result of strace for the command "yum clear all" as follows.
    > strace -f -F yum clear all
    ......
    stat64("/var/lib/rpm/DB_CONFIG", 0xbf93281c) = -1 ENOENT (No such file or directory)
    open("/var/lib/rpm/DB_CONFIG", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
    stat64("/var/lib/rpm/__db.001", {st_mode=S_IFREG|0644, st_size=24576, ...}) = 0
    open("/var/lib/rpm/__db.001", O_RDWR|O_LARGEFILE) = 3
    fcntl64(3, F_SETFD, FD_CLOEXEC) = 0
    fstat64(3, {st_mode=S_IFREG|0644, st_size=24576, ...}) = 0
    close(3) = 0
    open("/var/lib/rpm/__db.001", O_RDWR|O_LARGEFILE) = 3
    fcntl64(3, F_SETFD, FD_CLOEXEC) = 0
    mmap2(NULL, 24576, PROT_READ|PROT_WRITE, MAP_SHARED, 3, 0) = 0xb7a17000
    close(3) = 0
    stat64("/var/lib/rpm/__db.002", {st_mode=S_IFREG|0644, st_size=1318912, ...}) = 0
    open("/var/lib/rpm/__db.002", O_RDWR|O_LARGEFILE) = 3
    fcntl64(3, F_SETFD, FD_CLOEXEC) = 0
    mmap2(NULL, 1318912, PROT_READ|PROT_WRITE, MAP_SHARED, 3, 0) = 0xb78d5000
    close(3) = 0
    stat64("/var/lib/rpm/__db.003", {st_mode=S_IFREG|0644, st_size=450560, ...}) = 0
    open("/var/lib/rpm/__db.003", O_RDWR|O_LARGEFILE) = 3
    fcntl64(3, F_SETFD, FD_CLOEXEC) = 0
    mmap2(NULL, 450560, PROT_READ|PROT_WRITE, MAP_SHARED, 3, 0) = 0xb7867000
    close(3) = 0
    stat64("/var/lib/rpm/Packages", {st_mode=S_IFREG|0644, st_size=19869696, ...}) = 0
    open("/var/lib/rpm/Packages", O_RDONLY|O_LARGEFILE) = 3
    fcntl64(3, F_SETFD, FD_CLOEXEC) = 0
    read(3, "\0\0\0\0\1\0\0\0\0\0\0\0a\25\6\0\10\0\0\0\0\20\0\0\0\10"..., 512) = 512
    close(3) = 0
    open("/var/lib/rpm/Packages", O_RDONLY|O_LARGEFILE) = 3
    fcntl64(3, F_SETFD, FD_CLOEXEC) = 0
    fstat64(3, {st_mode=S_IFREG|0644, st_size=19869696, ...}) = 0
    futex(0xb78c587c, FUTEX_WAIT, 1, NULL
  • Solution
    remove the __db.* files under the /var/lib/rpm and retry running the yum command.

2008年12月12日金曜日

[Grails]Split Write Database Connection Plugin for master/slave configuration(Alpha version 0.2)

Please refer to the
http://taapps-javalibs.blogspot.com/2009/04/grailsupgraded-split-write-database.html

Grails Split Write Database Connection Plugin for master-slave configuration (Alpha version 0.2, like the magic multi connection for rails framework, multiple datasource)

After installing this plugin, we can split the read/write database connection and write any data to the other database and System will inject new methods into the Domain Classes named like saveXXXXX, lockXXXXX, deleteXXXXX, executeUpdateXXXXX method to split writing the data to the other databases.

Refer to the http://groups.google.com/group/taapps-sourcecode-libraries/web/grails-split-write-database-connection-plugin

2008年12月8日月曜日

[GRAILS]how to use the String type for the primary key column

How to use the String type primary key column in Domain Class on Grails environment.
  • the definition of the Domain Class
    class Test {
    //define id column as String type
    String id
    .....
    //define the id generator type, it should use the manual assignment
    static mapping={
    id generator:'assigned'
    }
    }
  • using this domain class
            def index = {
    //create new object defined the primary key as the String type.
    def test=new Test()

    def date=new Date()
    //set the unique value of primary key manually.
    test.setId("pk-${date.getTime()}")
    test.setMsg("Message")
    //save
    test.save()
    ...
    }

2008年10月6日月曜日

[grails]create plugin for grails to execute native query

I upgraded the new version file, please refer to the http://taapps-javalibs.blogspot.com/2009/04/grailsupgraded-plugin-for-grails-to.html

I create grails plugin named native-query to execute native query statement like ORACLE's query hint, mysql match-against statement on the grails framework.
I wrote a blog entry "[Groovy>Grails] Customization, how to execute Native SQL statement on Grails environment" before. but this customization is not useful. I create a new plugin having the same functionality.
  1. download zip file named grails-native-query-0.1.zip via http://groups.google.com/group/taapps-sourcecode-libraries/web/grails-native-query-0.1.zip
  2. installing plugin into the grails application
    grails install-plugin grails-native-query-0.1.zip

2008年9月11日木曜日

[WinVista]Not display and apply the Windows Vista Service Pack programs via Windows Update

This issue is not related to the java or java's libraries, this is windows vista issue.

Description
Windows Update program doesn't list the Windows Vista Service pack 1 and we can't apply the Window Vista Service Pack 1 via Windows Update program.

References
  1. Information about Windows Vista Service Pack
    http://support.microsoft.com/kb/936330/
  2. Windows Vista Service Pack 1 is not available for installation from Windows Update and is not offered by Automatic Updates
    http://support.microsoft.com/kb/948343
Cause
Before installing the Windows Vista Service Pack1, System needs to be applied all important programs and patches listed on Windows Update. System doesn't display and list the Vista Service Pack 1 until applying all important patches and updates.
(not require the optional programs. for example, we don't need to apply the patches for the silverlight even if the programs are listed on Windows Update.)
Maybe this problem doesn't occure when setting the automatically windows update mode.

Resolution

[WinVista]Error occured while installing windows vista service pack 1

This issue is not related to the java or java's libraries, this is windows vista issue.

Description
Error occured when installing the Windows Vista Service pack 1 on Vista Home Edition environment. I tried to install several times, but same error occured everytime.

References

Error details
Error message was as follows.
An internal error occured while installing the service pack.
Error Code: 0x0800F0826 See http://go.microsoft.com/fwlink/?linkid=101139

Cause
Before installing the Windows Vista Service Pack1, System needs to be applied all important programs and patches listed on Windows Update.
(not require the optional programs. for example, we don't need to apply the patches for the silverlight even if the programs are listed on Windows Update.)
Maybe this problem doesn't occure when setting the automatically windows update mode.

Resolution
  1. Open the Windows Update via Start Menu->Windows Vista or Open the Start Menu and enter the "Windows Update" in the search fields at the bottom of Start Menu.
  2. Check the important programs and patches you haven't applied yet listed on Windows Update.
  3. If you have any programs you haven't applied yet, please try to apply all of the programs marked as Important.
  4. After applying the programs listed on Windows Update, reboot the Windows machine.
  5. Retry to apply the Windows Service Pack program.
(Please look at the documentation "Information about Windows Vista Service Pack 1" and check the "What to do before you install Windows Vista SP1" section.)

2008年5月30日金曜日

[Firefox]blank page is displayed, not able to access to the localhost(127.0.0.1) when using Firefox browser.

Description
When I use the firefox browser in Windows Vista environment and access to my localhost environment to test my web page, I can't access to my localhost web page. blank page is found and firefox doesn't display my test page, and System has no response. However, Internet Explorer works fine in the same environment.

Resolution
  1. Start the firefox browser
  2. Type "about:config" in URL field, the configuration page is displayed.
  3. Type "ipv6" in Filter field located at the top of the config page.
  4. Check "network.dns.disableIPv6", the default value of this configuration is FALSE, change the value of this configuration to TRUE(doubleclick this field and system will change the value to TRUE.)

2008年5月26日月曜日

[Java>JavaMail] java.lang.SecurityException: "Access to default session denied" occures.

Description
This problem occures in my web application environment using tomcat server. When using the javamail library to send email from my application, sometimes the java.lang.SecurityException: "Access to default session denied" error occures and I can not send email from my application. After rebooting my application server(tomcat), javamail works fine for a while.

Error Details
Error message outputted by the javamail is java.lang.SecurityException: "Access to default session denied". After occuring this error, system always fails to send email, but system works fine after rebooting the tomcat server.

Cause
This error is raised in the getDefaultInstance method in javax.mail.Session.java. According to this source code, this error occures when the default session object is already initialized, but authenticator instance is renewed or changed, or the class loader of the default session object is different from the argument authentificator's. Maybe the java source code using the default session instance of the java mail is recompiled and reloaded, or duplicate javamail class libraries are included into the Classpath of the environment.
javax.mail.Session.java file
public static synchronized Session getDefaultInstance(Properties props,
Authenticator authenticator) {
if (defaultSession == null)
defaultSession = new Session(props, authenticator);
else {
// have to check whether caller is allowed to see default session
if (defaultSession.authenticator == authenticator)
; // either same object or both null, either way OK
else if (defaultSession.authenticator != null &&
authenticator != null &&
defaultSession.authenticator.getClass().getClassLoader() ==
authenticator.getClass().getClassLoader())
; // both objects came from the same class loader, OK
else
// anything else is not allowed
throw new SecurityException("Access to default session denied");
}

return defaultSession;
}

Resolution
  1. Recompile and restart application server to reload the new class file.
    After restarting the application server, does your system work fine?
    Do you use auto-deploy functionality? If yes, restart application server and use it without modifying and recompiling your java files.
  2. If the duplicate class files are included.
    Please check the class path directories and some jar files including the javamail class file is included. For example, please check common/lib directory and WEB-INF/lib in your application if you are using tomcat application server. If the duplicate class files are found, please remove the jar file.

2008年5月9日金曜日

[Groovy>Grails] IncompatibleClassChangeError error when starting jetty server in grails development environment

Description
I useally use the Java environment based on Sun's JDK when using grails and groovy, but sometimes I change the JDK from Sun's to IBM's to check the behavior and performance. After changing the IBM's JDK, following error occures when starting up the jetty application server on grails environment.

Error Detail
Failed startup of context org.mortbay.jetty.webapp.WebAppContext@3c003c{/test,/home/admin/test/web-app}
org.codehaus.groovy.runtime.InvokerInvocationException: java.lang.IncompatibleClassChangeError: the number of constructors during runtime and compile time for java.lang.Thread do not match. Expected 8 but got 9.

Solution
This error occures because the runtime of java version or provider(Sun, IBM or others) is different from the version of compiled jdk environment. In my case, I compile the grails source code based on Sun's jdk(Ver.1.5), and then I change the JDK from Sun to IBM(Ver.1.5) without recompiling my java source codes. Maybe the IBM internal classes using in the JDK is different from the Sun's. In this case, the error is resolved after clearing all old compiled class files and recompile all classes by using new java compiler.

2008年4月10日木曜日

[JAVA>Rome, Itunes RSS/XML] When using Rome ITunes RSS Reader, ParsingFeedException(Invalid XML) error occured.

When using Rome's itunes module, the error "com.sun.syndication.io.ParsingFeedException: Invalid XML" sometimes occures.The error stack is as follows. This error isn't related to the Rome core program, this error is depended on the itunes module.
The Podcast RSS feeds has itunes:duration attribute which means the duration of the podcast file. The value format of this field is always similar to "09:30", but some site are including the invalid value(Long type value).

References
  1. Same error, but the root cause is different from this problem.
    http://taapps-javalibs.blogspot.com/2008/04/javarome-rssxml-when-using-rome-rss.html
  2. Itunes module site
    http://wiki.java.net/bin/view/Javawsxml/ITunes
  3. Source Code repository
    https://rome.dev.java.net/source/browse/rome/
Error Stack
  • Caused by: java.lang.RuntimeException: Illegal time value: 9174935
    at com.sun.syndication.feed.module.itunes.types.Duration.(Duration.java:98)
    at com.sun.syndication.feed.module.itunes.io.ITunesParser.parse(ITunesParser.java:149)
    at com.sun.syndication.io.impl.ModuleParsers.parseModules(ModuleParsers.java:51)
    at com.sun.syndication.io.impl.BaseWireFeedParser.parseItemModules(BaseWireFeedParser.java:57)
    at com.sun.syndication.io.impl.RSS090Parser.parseItem(RSS090Parser.java:289)
    at com.sun.syndication.io.impl.RSS091UserlandParser.parseItem(RSS091UserlandParser.java:222)
    at com.sun.syndication.io.impl.RSS092Parser.parseItem(RSS092Parser.java:81)
    at com.sun.syndication.io.impl.RSS093Parser.parseItem(RSS093Parser.java:39)
    at com.sun.syndication.io.impl.RSS094Parser.parseItem(RSS094Parser.java:68)
    at com.sun.syndication.io.impl.RSS090Parser.parseItems(RSS090Parser.java:263)
    at com.sun.syndication.io.impl.RSS090Parser.parseChannel(RSS090Parser.java:178)
    at com.sun.syndication.io.impl.RSS091UserlandParser.parseChannel(RSS091UserlandParser.java:84)
    at com.sun.syndication.io.impl.RSS092Parser.parseChannel(RSS092Parser.java:49)
    at com.sun.syndication.io.impl.RSS094Parser.parseChannel(RSS094Parser.java:45)
    at com.sun.syndication.io.impl.RSS090Parser.parse(RSS090Parser.java:82)
    at com.sun.syndication.io.WireFeedInput.build(WireFeedInput.java:252)
    at com.sun.syndication.io.WireFeedInput.build(WireFeedInput.java:179)
The reason why this error occures.
When system reads the RSS, Rome and itunes module parses the rss feed. In Duration field, ITuneParser tries to check whether the duration value includes the ":" character or not. But some duration field doesn't include the ":" character, ITuneParser will raise the ParseException.

Solution
Please download the latest source code from the CVS repository, this problem has already solved. I downloaded the latest source code and compiled it. You can get the jar file I compiled.
URL is http://groups.google.com/group/taapps-sourcecode-libraries/web/itunes-0.4-tafix2.jar
(I recompiled itues-0.4.jar file again at 2008/04/14)

2008年4月4日金曜日

[JAVA>Rome, RSS/XML] When using Rome RSS Reader, ParsingFeedException(Invalid XML) error occured.

References
  1. Rome WebSite
    https://rome.dev.java.net/
Problems
When using Rome RSS Reader, "com.sun.syndication.io.ParsingFeedException: Invalid XML" error sometimes occures.This problem occure while parsing the RSS feed and System raises the ParsingFeedException and NumberFormatException.

Error Stack when occuring this problem
com.sun.syndication.io.ParsingFeedException: Invalid XML
com.sun.syndication.io.ParsingFeedException: Invalid XML
at com.sun.syndication.io.WireFeedInput.build(WireFeedInput.java:185)
at com.sun.syndication.io.SyndFeedInput.build(SyndFeedInput.java:122)
at RomeTest.main(RomeTest.java:35)
Caused by: java.lang.NumberFormatException: For input string: "09:31"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:63)
at java.lang.Long.parseLong(Long.java:427)
at java.lang.Long.parseLong(Long.java:476)
at com.sun.syndication.io.impl.RSS092Parser.parseItem(RSS092Parser.java:107)
at com.sun.syndication.io.impl.RSS093Parser.parseItem(RSS093Parser.java:39)
at com.sun.syndication.io.impl.RSS094Parser.parseItem(RSS094Parser.java:68)
at com.sun.syndication.io.impl.RSS090Parser.parseItems(RSS090Parser.java:263)
at com.sun.syndication.io.impl.RSS090Parser.parseChannel(RSS090Parser.java:178)
at com.sun.syndication.io.impl.RSS091UserlandParser.parseChannel(RSS091UserlandParser.java:84)
at com.sun.syndication.io.impl.RSS092Parser.parseChannel(RSS092Parser.java:49)
at com.sun.syndication.io.impl.RSS094Parser.parseChannel(RSS094Parser.java:45)
at com.sun.syndication.io.impl.RSS090Parser.parse(RSS090Parser.java:82)
at com.sun.syndication.io.WireFeedInput.build(WireFeedInput.java:252)
at com.sun.syndication.io.WireFeedInput.build(WireFeedInput.java:179)
Reason why this errr occured
Some RSS data has a enclosure tag in channel/item element as follows and length parameter is defined in enclosure element.
 enclosure url="http://domain.com/file.mp3" length="123456789" type="audio/mpeg"
According to the wikipedia(http://en.wikipedia.org/wiki/RSS_Enclosures) or other web site(http://www.w3schools.com/rss/rss_tag_enclosure.asp), the length parameter means the length (in bytes) of the media file and this parameter is required field. The length parameter should be numerical value, but sometimes it isn't numerical in some RSS feeds.(In some feeds, the value of length parameter includes the comma separator like "123,456,789", or other RSS includes the "09:31" value similar to the timestamp)
In this case, while System tries to convert the length parameter from String object to Long object by using java.lang.Long.parseLong method, System throws the NumberFormatException because the value in the length field has invalid format value.

Solution
  1. Fixed file
    rome-0.9/src/java/com/sun/syndication/io/impl/RSS092Parser.java
  2. Fixed function
    Change as follows in parseItem() function.
  3. Description
    catches the exception while converting the String object to Long for the Length parameter.
    In case of my fix, catches the NumberFormatException and then, tries to remove the comma characters from the parameter and retry the conversion. retry is failed, ignore occuring this exception and doesn't set the value inf Length attribute.
  4. Fixed file
    Jar File: http://groups.google.com/group/taapps-sourcecode-libraries/web/rome-0.9-tafix.jar
    This jar file includes both this fix and http://taapps-javalibs.blogspot.com/2007/06/javarome-rss-when-using-rome-rss-reader.html problem.
  5. Fix Example
        att = e.getAttributeValue("length");//getRSSNamespace()); DONT KNOW WHY DOESN'T WORK
    if (att!=null && att.trim().length()>0) {
    //Starting customization, added by tatsuya anno(taapps@gmail.com)
    //sometimes occures com.sun.syndication.io.ParsingFeedException
    //when converting the attribute value to the Long
    String trimmedAtt=att.trim();
    long enclosureLength=-1;
    try{
    enclosureLength=Long.parseLong(trimmedAtt);
    }catch(Exception exception){
    try{
    //remove commma character before converting
    //string to long.
    trimmedAtt=trimmedAtt.replaceAll(",","");

    //retry conversion from string to long
    //if exception occures, system will ignore it
    //in this case
    enclosureLength=Long.parseLong(trimmedAtt);
    }catch(Exception ignore){}
    }

    //if enclosureLength is greater than 0, set length
    if(enclosureLength>=0){
    enclosure.setLength(enclosureLength);
    }
    //end of customization
    }

2008年3月29日土曜日

[Groovy>Grails] Customization, how to execute Native SQL statement on Grails environment

I created a new plugin, please refer to http://taapps-javalibs.blogspot.com/2009/04/grailsupgraded-plugin-for-grails-to.html

Description

Grails is an open-source web application framework that leverages the Groovy language and complements Java Web development. Grails has the database access layer like the RubyOnRails's Active Record, it is very usefull and powerful, but sometimes we need to execute Native SQL Statement. We sometimes need to use the fulltext search statement(match/against statement) if we use mysql database as the backend server. We sometimes need to tune the sql performance and enter the QueryHint into the sql statenent.In case of ORACLE Database, we can use query hint like "select /*index hint */ .....", in case of using mysql, we can use "use/force index" statement.
But now, we can use these native sql statement on Grails framework, Grails System doesn't allow to use native statement.(We can use HQL Query Language by using executeQuery, findAll or other methods, but HQL doesn't allow to use native sql via these methods). I customized grails and added the "executeNativeQuery" method to run the native sql statement from the Grails framework.

Installation
(I tested this customization only on mysql database environment.)
  1. Download grails-1.0.1-dist-b4.tar file, this file is customized based on Grails-1.0.1 source code.
    jar files: http://groups.google.com/group/taapps-sourcecode-libraries/web/grails-1.0.1-dist-b4.tar
  2. Extract downloaded tar file
    source files: http://taapps-sourcecode-libraries.googlegroups.com/web/grails-1.0.1-b4-src.tar
  3. Copy 8 *.jar files existing under dist directory to the GRAILS_HOME/dist directory
  4. Restart application server, defailt server is jetty
How to use this customization program
While restarting the application server, System adds the executeNativeQuery method into the Domain Class object dynamically. The executeNativeQuery method has some parameters as follows and return the List object including some DomainClass objects fetched from the database.
Examples how to use this method are as follows.(the name "IndTest" means my Domain Test class name for the sample code)
  • Type1, put the raw SQL statement into the grails hibernate layer.
    Table alias name should be "tbl", the "tbl" alias will be mapped to the Domain Class.

    def objList=IndTest.executeNativeQuery(
    "select {tbl.*} from ind_test as {tbl} where user_id=10000 and match(description) against('aaaaaaa')")

    objList.each{obj-> //executeNativeQuery will return the List object including the fetched domain objects
    .....
    }

  • Type2 executeNativeQuery has 3 arguments, SQL Statement String, Map object for mapping table alias, List object including the bind parameter values.

    def objList=IndTest.executeNativeQuery(
    "select {alias.*} from ind_test as {alias} where user_id=? and match(description) against(?)",
    [alias:IndTest], --> table alias "alias" is mapped to the IndTest Domain Class.
    [10000,"bbbbbb"]) --> 10000 is replaced with user_id's, bbbbbb is replaced with description's

  • Type3 executeNativeQuery has 3 arguments, SQL Statement String, Map object for mapping table alias, Map object including the bind parameter values.

    def objList=IndTest.executeNativeQuery(
    "select {alias.*} from ind_test as {alias} where user_id=:p1 and match(description) against(:p2)",
    [alias:IndTest],
    [p1:10000, p2:"cccccc"])

  • Type4 executeNativeQuery has 4 arguments, SQL Statement String, Map object for mapping table alias, Map object including the bind parameter values, Map object for using pagination

    def objList=IndTest.executeNativeQuery(
    "select {alias.*} from ind_test as {alias} where user_id=:p1 and match(description) against(:p2)",
    [alias:IndTest],
    [p1:10000,p2:"dddddd"],
    [max:10,offset:1])


  • executeNativeQuery method has other parameter patterns as follows.
    Query means the sql query statement string.
    EntityMap means the Map object including the table alias mapping(alias name and Domain class name).
    ParamList means the List object including the parameter values for the bind parameters.
    NamedMap means the Map object including the parameter values for the bind parameters.
    PageMap means the Map object for using pagination parameter.

    Arg Number :0 1 2 3
    Type 1 :String :Query
    Type 2 :String Map :Query,EntityMap
    Type 3 :String Map List :Query,EntityMap,ParamList
    Type 4 :String Map Map :Query,EntityMap,NamedMap
    Type 5 :String Map List Map :Query,EntityMap,ParamList,PageMap
    Type 6 :String Map Map Map :Query,EntityMap,NamedMap,PageMap


2008年3月8日土曜日

[Groovy>Grails] Error "failed to create task or type native2ascii" occures when running grails war file on Tomcat environment

Description
When running grails war file on Tomcat environment, following error message occures and fail to execute the program.

Error Message
 : Problem: failed to create task or type native2ascii
Cause: the class org.apache.tools.ant.taskdefs.optional.Native2Ascii was not found.
This looks like one of Ant's optional components.
Solution
System can not find the ant-nodeps.jar file in the classpath.
Get ant-nodeps.jar file and put this file into the $TOMCAT_HOME/webapps/[app name]/WEB-INF/lib/ and restart Tomcat process. ant-nodeps.jar file is including Apache ant file.

[Groovy>Grails]Database Dialect

Description
Grails Framework uses the Hibernate object/relational persistence and query service Tools between Database and Application. We sometimes have to compatible with various kind of Database. For example, We need to add the "create table" statement with Engine Type Dialect in case of using MySQL DB. It can handle the different dialects by using "dialect" variable in the DataSource.groovy configuration file.

References
  • Grails Home
    http://grails.codehaus.org/
  • Hibernate
    http://www.hibernate.org/
  • http://hartsock.blogspot.com/2007/11/grails-datasource-legacy-database-and.html
Solution
We can specify the hibernate database dialect class into the "dialect" variable in the grails-app/conf/DataSource.groovy Configuration file to handle the Database dialects. In case of using MySQL, we can add
"dialect=org.hibernate.dialect.MySQLInnoDBDialect" or "dialect=org.hibernate.dialect.MySQLMyISAMDialect"
into this file to handle the storage engines of database tables.
Please check the Dialect classes if you need to handle other database dialects.
http://www.hibernate.org/hib_docs/v3/api/org/hibernate/dialect/Dialect.html

Example of DataSource.groovy file under the grails-app/conf directory
  dbCreate = "create-drop" // one of 'create', 'create-drop','update'
url = "jdbc:mysql://localhost:5000/test_database
driverClassName = "com.mysql.jdbc.Driver"
username = "epic_admin"
password = "tskr0511epic"
//dialect = org.hibernate.dialect.MySQLInnoDBDialect
dialect = org.hibernate.dialect.MySQLMyISAMDialect

2008年1月6日日曜日

[Java>Original]Useful String Utility(Utility to use String Object)

String Utility, converter, check routine, and compare method to avoid NullPointerException or other Exception.

References
  • http://math.hws.edu/eck/cs124/javanotes4/c4/ex-4-1-answer.html
  • http://forum.java.sun.com/thread.jspa?threadID=442797&messageID=2013116
Original Source Code
  • http://taapps-sourcecode-libraries.googlegroups.com/web/Str.java
  • http://taapps-sourcecode-libraries.googlegroups.com/web/taapps-bnr-0.2.jar
Methods
  • Convert first letter of words to capitalized letter.
    String testStr3=Str.getCapitalizedFirstLetter("capitalIZED fiRSt leTTER");
    Output of testStr3 object is "Capitalized First Letter"
  • Compare 2 String objects
    Compare 2 String objects and check whether the value of String object are the same or not. You don't need to check null of String object before calling this method.
    Third argument compare 2 strings ignore case
    String test1="Test1";
    String test2="test1";
    //case sensitive
    boolean result=Str.isSame(test1,test2,false));
    //result is false

    //ignore case Pattern
    result=Str.isSame(test1,test2,true));
    //result is true because comparing 2 string by using equalsIgnoreCase function
  • nvl(return the second object if the first argument object is null)
    Function return the second argument object if the first argument is null. This function works like ORACLE PL/SQL's nvl function.
    String test1=null;
    String test2="test1";
    String test3=Str.nvl(test1,test2);
    //test3 is "test1" because test1 object is null
    String test4=Str.nvl(test3,test2);
    //test4 is same as test3 object
  • padding and format number
    //right padding with @ char
    String paddingRight=Str.padStr("12345",20,'@',Str.NUMBER_PADDING_RIGHT);
    //Output is 12345@@@@@@@@@@@@@@@
    //left padding with X char
    String paddingLeft =Str.padStr("12345",20,'X',Str.NUMBER_PADDING_LEFT);
    //Output is XXXXXXXXXXXXXXX12345
  • padding with 0
    String padTest1=Str.padWithZero(12345,20);
    //Output of padTest1 String is 00000000000000012345
  • indexOf
    String test1="Test1";
    String test2="test1";
    boolean result=Str.indexOf(test1,test2,false));
    //result is false
    boolean result=Str.indexOf(test1,test2,true));
    //result is true
  • split string
    String test1="test1,test2,test3,test4,test5";
    String[] splittedStrs=Str.splitStr(test1,",")
  • Check whether the value of second argument is being included into the first argument array or not. Third argument is ignorecase flag.
    String[] array=new String[]{"test1","test2","test3","test4"};
    boolean result=Str.checkContain(array,"TEST3",false);
    //result is false

    //ignore case pattern
    boolean result=Str.checkContain(array,"TEST3",true);
    //result is true
  • Concatenate string array with second argument separator string
    String[] array=new String[]{"test1","test2","test3","test4"};
    String concat=Str.concat(array,"--");
    Output of concat Object is test1--test2--test3--test4
  • Check Utility(String length and format)
    • checkLength
    • checkCharsExpression
    • checkLengthAndExpression
  • URL encoder and decoder
    • decodeUrl
      encodeUrl

2008年1月5日土曜日

[Java>Jcaptcha]CaptchaServiceException occures and validation is always failed when the browser's cookie is disabled.

CaptchaServiceException occures and validation is always failed when the browser's cookie is disabled.

References
  • JCaptcha Home
    http://jcaptcha.sourceforge.net/
  • jcaptcha 5 minutes application integration tutorial http://forge.octo.com/jcaptcha/confluence/display/general/5+minutes+application+integration+tutorial
Description
When the browser's Cookies is disabled, the CaptchaServiceException always occures and validation is always failed. When the browser's cookie function is changed to be enabled, Capthca validation works fine without erroring out.
(When the browser's Cookies is disabled, I access url of the custom signup form with the session id manually like this "http://localhost/signup/;jsessionid=XXXXXXXXXX?app_name=test".)
My source code of Image Captcha Servlet and Captcha Service is based on the application integration tutorial(refer to the JCaptcha homepage http://forge.octo.com/jcaptcha/confluence/display/general/5+minutes+application+integration+tutorial), but it doesn't work when the browser's cookie function is disabled.

Error Detail
Exception occures as follows when validation is failed.
com.octo.captcha.service.CaptchaServiceException: Invalid ID, could not validate unexisting or already validated captcha
This exception is written in com.octo.captcha.service.AbstractCaptchaService. validateResponseForID method and this error is raised when checking and validating the captcha response.

Cause
JCaptcha use the session id as a key to store the value of captcha into the Map Object(when using DefaultManageableImageCaptchaService()). When accessing the Image Captcha Servlet to get captcha image, System can't get session id properly in case of disabling the browser cookie.

Solution
When accessing the Image Captcha Servlet to get captcha, image tag is always as follows.
<img id="captchaImage" src="/jcaptcha" border="1" />
But it should be changed as follows.
<img id="captchaImage" src="/jcaptcha;jsessionid=XXXXXXXXXX" border="1" />
The image tag is should be with the value of session id manually if the browser's cookie is disabled. the value of "XXXXXXXXXX" replaces with the client's session id.