<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-9333605</id><updated>2011-11-27T23:51:28.555Z</updated><category term='UNIX'/><category term='logging'/><category term='weblog'/><category term='MySQL'/><category term='XSLT'/><category term='WTP'/><category term='vi'/><category term='CSS'/><category term='Accessibility'/><category term='sorting'/><category term='remote'/><category term='JSTL'/><category term='XML'/><category term='tomcat'/><category term='Java'/><category term='networking'/><category term='sed'/><category term='test'/><category term='grails'/><category term='Access'/><category term='XPath'/><category term='groovy'/><category term='html'/><category term='Eclipse'/><category term='servlet'/><category term='Hacking'/><category term='Log4J'/><category term='Regular Expression'/><category term='svn'/><category term='Excel'/><title type='text'>Jianfeng Tian</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>80</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-9333605.post-8907295701251142524</id><published>2011-11-03T10:27:00.000Z</published><updated>2011-11-03T10:27:49.466Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='test'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Initialising in Grails Service</title><content type='html'>Attributes can be initialised from config in grails service by implementing the Spring &lt;a href="http://static.springsource.org/spring/docs/2.5.5/api/org/springframework/beans/factory/InitializingBean.html"&gt;InitializingBean&lt;/a&gt; interface. In the afterPropertiesSet method, set the attributes. &lt;br /&gt;&lt;br /&gt;class SomeService implements InitializingBean {&lt;br /&gt;  def grailsApplication&lt;br /&gt;  private static String TOKEN&lt;br /&gt;&lt;br /&gt;  void afterPropertiesSet() {&lt;br /&gt;    TOKEN = grailsApplication.config.token&lt;br /&gt;    println this&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  def someMethod() {&lt;br /&gt;    println TOKEN&lt;br /&gt;    println this&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;In unit and integration test, the afterPropertiesSet method has to be called otherwise the TOKEN won't be set. But noticeably, in unit test, the instances printed out by 'println this' are different, although grails service by default is a singleton implementation; but in integration test, the instance from 'println this' is the same. &lt;br /&gt;&lt;br /&gt;In unit test: &lt;br /&gt;&lt;br /&gt;@Before&lt;br /&gt;  void setUp() {&lt;br /&gt;    service.afterPropertiesSet()&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;In integration test:&lt;br /&gt;&lt;br /&gt;private static service&lt;br /&gt;&lt;br /&gt;@BeforeClass&lt;br /&gt;static void fixtureSetUp() {&lt;br /&gt;  service.afterPropertiesSet()&lt;br /&gt;}&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-8907295701251142524?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/8907295701251142524/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=8907295701251142524' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/8907295701251142524'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/8907295701251142524'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2011/11/initialising-in-grails-service.html' title='Initialising in Grails Service'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-8211078791011670395</id><published>2011-10-22T09:50:00.000+01:00</published><updated>2011-10-22T09:50:32.571+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Grails Service Singleton</title><content type='html'>Jeff Brown explained Grails singleton service in &lt;a href="http://grails.1312388.n4.nabble.com/How-to-choose-the-Service-Scope-in-grails-project-td1385262.html"&gt;Nabble&lt;/a&gt;. Below is his description.&lt;br /&gt;&lt;br /&gt;"If your service has an instance variable (that is state) and you don't want that state to be shared by multiple concurrent users of the service, then you don't want that service to be a singleton.  If a service is a singleton then every user of that service is sharing the same copy of the service.  If a service is request scoped then a new instance is created for every http request.  If a service is sessions scoped then the service will be kept around and reused for the entire user session (each user session has their own copy). "&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-8211078791011670395?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/8211078791011670395/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=8211078791011670395' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/8211078791011670395'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/8211078791011670395'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2011/10/grails-service-singleton.html' title='Grails Service Singleton'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-5079645145719207463</id><published>2011-10-20T17:52:00.000+01:00</published><updated>2011-10-20T17:52:15.962+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Cannot get property 'config' on null object in Grails Integration Test</title><content type='html'>Class someService {&lt;br /&gt;&lt;br /&gt;  def grailsApplication&lt;br /&gt;&lt;br /&gt;  def someMethod() {&lt;br /&gt;    &lt;br /&gt;    def attribute = grailsApplication.config.someAttribute&lt;br /&gt;    return attribute&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;When running integration test, &lt;br /&gt;&lt;br /&gt;Class someServiceTests {&lt;br /&gt;&lt;br /&gt;  @Test&lt;br /&gt;  void testSomeMethod() {&lt;br /&gt;    def service = new SomeService()&lt;br /&gt;    def attribute  = service.someMethod()&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;It will complain that: &lt;br /&gt;&lt;br /&gt;"java.lang.NullPointerException: Cannot get property 'config' on null object"&lt;br /&gt;&lt;br /&gt;The way around this is, in the integration test, add the following line:&lt;br /&gt;&lt;br /&gt;service.grailsApplication = new DefaultGrailsApplication()&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-5079645145719207463?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/5079645145719207463/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=5079645145719207463' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/5079645145719207463'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/5079645145719207463'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2011/10/cannot-get-property-config-on-null.html' title='Cannot get property &apos;config&apos; on null object in Grails Integration Test'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-8509693728994942927</id><published>2011-09-15T15:48:00.002+01:00</published><updated>2011-09-15T23:12:10.530+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Mock grailsApplication and config in Unit Test</title><content type='html'>grailsApplication can be injected in controller before 2.0.0, and it is still the case for 2.0.0&lt;br /&gt;&lt;br /&gt;Before grails 2.0.0, you can only access your config in the service by calling ConfigurationHolder.config. But now with Grails 2.0.0, grailsApplication can be injected in service. &lt;br /&gt;&lt;br /&gt;In unit test, we should do the following, so that the grailsApplication and config is mocked properly. &lt;br /&gt;&lt;br /&gt;service.grailsApplication = [config.config]&lt;br /&gt;&lt;br /&gt;controller.grailsApplication = [config: config]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-8509693728994942927?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/8509693728994942927/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=8509693728994942927' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/8509693728994942927'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/8509693728994942927'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2011/09/mock-grailsapplication-and-config-in.html' title='Mock grailsApplication and config in Unit Test'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-494765179891044251</id><published>2011-09-12T11:53:00.000+01:00</published><updated>2011-09-12T11:53:06.880+01:00</updated><title type='text'>Specify your own environment in Grails</title><content type='html'>environments {&lt;div&gt;&amp;nbsp; foo {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; settings = 'bar'&lt;/div&gt;&lt;div&gt;&amp;nbsp; }&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To specify your environment:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;grails -Dgrails.env=foo&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-494765179891044251?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/494765179891044251/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=494765179891044251' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/494765179891044251'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/494765179891044251'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2011/09/specify-your-own-environment-in-grails.html' title='Specify your own environment in Grails'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-2172790475932580960</id><published>2011-06-08T12:00:00.000+01:00</published><updated>2011-06-08T12:00:02.333+01:00</updated><title type='text'>Proxy setting</title><content type='html'>If you are behind firewall, and your application need internet connection, then put the following code in your ~/.bash_profile&lt;br /&gt;&lt;br /&gt;JAVA_OPTS="-Dhttp.proxyHost=yourProxyFileName -Dhttp.proxyPort=8080"&lt;br /&gt;export JAVA_OPTS&lt;br /&gt;&lt;br /&gt;Then refresh the console using:&lt;br /&gt;&lt;br /&gt;. ~/.bash_profile&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-2172790475932580960?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/2172790475932580960/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=2172790475932580960' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/2172790475932580960'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/2172790475932580960'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2011/06/proxy-setting.html' title='Proxy setting'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-6531467535723237443</id><published>2011-02-10T17:34:00.000Z</published><updated>2011-02-10T17:34:47.167Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Reload External Config File Dynamically</title><content type='html'>If the grails application's Config.groovy file is changed, the war file has to be regenerated to reflect the changes, and the war has to be redeployed onto the server. This process normally involves: &lt;br /&gt;&lt;br /&gt;1. Generate the grails application war file.&lt;br /&gt;2. Go to the tomcat manager console &lt;br /&gt;3. Click "Undeploy" to remove the application's context. &lt;br /&gt;4. Upload the newly generated war to the ${tomcat}/webapps directory&lt;br /&gt;&lt;br /&gt;Adding an external config file (like the code below) in the Config.groovy file does allow not to re-generate the war file. It does allow you to define sensible configuration info (e.g. username, password, access allowed users, etc.) in an external file rather than packed within the generated war file.&lt;br /&gt;&lt;br /&gt;grails.config.locations = [ "file:${userHome}/.grails/CoursePackApp/${appName}-config.groovy"]&lt;br /&gt;&lt;br /&gt;However the web application doesn't load the changes in the external config file automatically, thus the application has to be stopped and re-started. This process normally involves: &lt;br /&gt;&lt;br /&gt;1. Go to the tomcat manager console&lt;br /&gt;2. Click "stop" to stop the  application&lt;br /&gt;3. Click "start" to start the application, so that the application can pick up the changes in the external config file.&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;To avoid the above hassle (i.e. regenerating the war file, restarting the application) every time we change the .&lt;br /&gt;&lt;br /&gt;In the grails-app/conf/Config.groovy file, add:&lt;br /&gt;&lt;br /&gt;grails.config.locations = ["file:${userHome}/.grails/YourPath/${appName}-config.groovy"]&lt;br /&gt;&lt;br /&gt;On the server, create the external file at:&lt;br /&gt;&lt;br /&gt;/userHome/.grails/YourPath/CoursePackApp-config.groovy&lt;br /&gt;&lt;br /&gt;In a controller which is the entry point to the application (i.e. Login Controller), add the code below. Thus every time this controller action is accessed, the external config is re-loaded.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: groovy"&gt;// Courtesy IntelliGrape http://bit.ly/aHZRjZ&lt;br /&gt;&lt;br /&gt;// access external config file&lt;br /&gt;&lt;br /&gt;def config = ConfigurationHolder.config&lt;br /&gt;def locations = config.grails.config.locations&lt;br /&gt;&lt;br /&gt;locations.each {&lt;br /&gt; String configFileName = it.split("file:")[1]&lt;br /&gt; config.merge(new ConfigSlurper().parse(new File(configFileName).text))&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-6531467535723237443?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/6531467535723237443/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=6531467535723237443' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/6531467535723237443'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/6531467535723237443'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2011/02/reload-external-config-file-dynamically.html' title='Reload External Config File Dynamically'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-6918015492224854521</id><published>2010-11-25T15:09:00.002Z</published><updated>2010-12-09T16:38:18.698Z</updated><title type='text'>Mocking Command Object in Grails</title><content type='html'>&lt;pre class="brush: groovy"&gt;Class PersonCommand {&lt;br /&gt;  String firstname&lt;br /&gt;  String lastname&lt;br /&gt;&lt;br /&gt;  static constraints = {&lt;br /&gt;    firstname(blank: false)&lt;br /&gt;    lastname(blank: false)&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre class="brush: groovy"&gt;Class PersonController {&lt;br /&gt;  def save {PersonCommand cmd -&gt;&lt;br /&gt;    if (cmd.hasErrors()) {&lt;br /&gt;      ...&lt;br /&gt;    }&lt;br /&gt;    else {&lt;br /&gt;      render (view: 'confirm', model: [person: cmd])&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Create an instance of that command object and pass it to the action. Below also shows the way to pass on a map of parameters to construct the command object. This needs the help of the metaClass.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: groovy"&gt;import grails.plugin.spock.ControllerSpec&lt;br /&gt;&lt;br /&gt;Class PersonControllerSpec extends ControllerSpec {&lt;br /&gt;  def 'save action' () {&lt;br /&gt;    given "":&lt;br /&gt;    mockCommandObject(PersonCommand)&lt;br /&gt;    Map mp = [firstname: 'joe', lastname: 'blog']&lt;br /&gt;    controller.metaClass.getParams { -&gt; mp}&lt;br /&gt;&lt;br /&gt;    when : "person form parameters are submitted"&lt;br /&gt;    // This works&lt;br /&gt;    // def cmd = new PersonCommand(firstname: 'joe', lastname: 'blog')&lt;br /&gt;&lt;br /&gt;    // This works better as it allows to pass on a map of parameters&lt;br /&gt;    def cmd = new PersonCommand(mp)&lt;br /&gt;&lt;br /&gt;    // Call the action&lt;br /&gt;    controller.save(cmd)&lt;br /&gt;&lt;br /&gt;    then : "the command object should be valid"&lt;br /&gt;    assert cmd.valid()&lt;br /&gt;&lt;br /&gt;    and : "the right model and view can be retrieved"&lt;br /&gt;    renderArgs.view = 'confirm'&lt;br /&gt;    renderArgs.model.person.firstname == 'joe'&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Note that the mockCommandObject only works when doing controller unit test, not domain unit test.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-6918015492224854521?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/6918015492224854521/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=6918015492224854521' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/6918015492224854521'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/6918015492224854521'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2010/11/mocking-command-object-in-grails.html' title='Mocking Command Object in Grails'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-4249732874619672244</id><published>2010-11-19T10:29:00.000Z</published><updated>2010-11-19T10:29:49.215Z</updated><title type='text'>Grails with customised ID Generator</title><content type='html'>&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-4249732874619672244?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.softwareinsane.com/2009/11/grails-with-mixed-externalinternal-id.html' title='Grails with customised ID Generator'/><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/4249732874619672244/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=4249732874619672244' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/4249732874619672244'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/4249732874619672244'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2010/11/grails-with-customised-id-generator.html' title='Grails with customised ID Generator'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-5456573470884952672</id><published>2010-11-15T12:31:00.000Z</published><updated>2010-11-15T12:31:47.699Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='test'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Grails Controller Unit Test with setting params as a map</title><content type='html'>When running controller unit test. Setting the params individually like below works fine &lt;br /&gt;&lt;br /&gt;controller.params.firstname = 'joe' &lt;br /&gt;controller.params.lastname = 'blog' &lt;br /&gt;&lt;br /&gt;However, if setting the params using a map like below: &lt;br /&gt;&lt;br /&gt;controller.params = [firstname: 'joe', lastname: 'blog'] &lt;br /&gt;&lt;br /&gt;It would throw exceptions: &lt;br /&gt;&lt;br /&gt;groovy.lang.ReadOnlyPropertyException: Cannot set readonly property: params for class: &lt;br /&gt;&lt;br /&gt;As suggested by Richard Bradley and Amit Jain in &lt;a href="http://grails.1312388.n4.nabble.com/Controller-Unit-Test-problem-while-params-as-a-map-td3039994.html"&gt;Grails mailing list&lt;/a&gt;, there are two solutions: &lt;br /&gt;&lt;br /&gt;With groovy meta programming: &lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: groovy"&gt;controller.metaClass.getParams { -&gt;&lt;br /&gt; [firstname: 'Joe', lastName: 'blog']&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Or use the putAll on the params:&lt;br /&gt;&lt;br /&gt;&lt;pre  class="brush: groovy"&gt;Map myParams = [firstname: 'joe', lastname: 'blog']&lt;br /&gt;controller.params.putAll(myParams)&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-5456573470884952672?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/5456573470884952672/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=5456573470884952672' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/5456573470884952672'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/5456573470884952672'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2010/11/grails-controller-unit-test-with.html' title='Grails Controller Unit Test with setting params as a map'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-1957227948521984807</id><published>2010-11-11T15:51:00.005Z</published><updated>2010-11-11T16:20:46.206Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='test'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Integration Testing Mail function with Greenmail and Spock in Grails</title><content type='html'>Just managed to do spock integration test on my mail function running on grails.&lt;br /&gt;&lt;br /&gt;I am using grails: 1.3.5,&amp;nbsp;mail: &amp;nbsp;0.9, &amp;nbsp;spock: 0.4-groovy-1.7,&amp;nbsp;greenmail: 1.2.1&lt;br /&gt;&lt;br /&gt;RegistrationService will save the person's registration record to the database and then send a confirmation email to the person.&lt;br /&gt;&lt;pre class="brush: groovy"&gt;class RegistrationService {&lt;br /&gt;def registrate (def person) {&lt;br /&gt;person.save(faileOnError: true)&lt;br /&gt;// when using mail plugin, mailService is automatically injected so we don't have to declare it.&lt;br /&gt;// also valid: mailService.sendMail&lt;br /&gt;sendMail {&lt;br /&gt;multipart true&lt;br /&gt;subject "Hello World"&lt;br /&gt;to person.emailAddress&lt;br /&gt;from "sender@test.com"&lt;br /&gt;body (view: '/email/confirm',&amp;nbsp;model: [person: person])&lt;br /&gt;}&lt;br /&gt;return person&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;To make greenmail integration work, make sure the following settings in the Config.groovy test environment. Please make sure there is no real mail server setting there, and also no real mail server settings in the conf/spring/resources.xml, otherwise a real email will be sent. Bear in mind, by using greenmail plugin for integration test, there is no real mail sent. &lt;br /&gt;&lt;br /&gt;Previously I was doing refactoring on someone else's code and got stuck on receiving real email and fail the integration test. Thanks to Mike Hugo on &lt;a href="http://grails.1312388.n4.nabble.com/Greenmail-problems-td3037671.html"&gt;nabble&lt;/a&gt; to pinpoint this. Here comes the settings in Config.groovy test environment:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: groovy"&gt;test {&lt;br /&gt;  grails.mail.port = com.icegreen.greenmail.util.ServerSetupTest.SMTP.port&lt;br /&gt;  grails.mail.host = "localhost"&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;The spock integration test is as below:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: groovy"&gt;import grails.plugin.spock.*;&lt;br /&gt;import com.icegreen.greenmail.util.*&lt;br /&gt;&lt;br /&gt;class RegistrationServiceIntegrationSpec extends IntegrationSpec{&lt;br /&gt;def greenMail&lt;br /&gt;&lt;br /&gt;def "create registration and send email"() {&lt;br /&gt;given:&lt;br /&gt;def service = new RegistrationService()&lt;br /&gt;&lt;br /&gt;when: "a user makes a valid registration" &lt;br /&gt;def person = new Person(title: 'Mr', lastName: 'joe',&lt;br /&gt;firstName: 'blog', 'dateOfBirth': new Date(),&lt;br /&gt;emailAddress: 'receipt@test.com'&lt;br /&gt;)&lt;br /&gt;assert person.validate(), true&lt;br /&gt;person == service.registrate(person)&lt;br /&gt;&lt;br /&gt;then: "the registration should be successful and the confirmation email should be sent successfully"&lt;br /&gt;assert 1 == greenMail.getReceivedMessages().length&lt;br /&gt;&lt;br /&gt;def message = greenMail.getReceivedMessages()[0]&lt;br /&gt;assert "sender@test.com" == GreenMailUtil.getAddressList(message.from)&lt;br /&gt;assert "Hello World" == message.subject&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-1957227948521984807?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/1957227948521984807/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=1957227948521984807' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/1957227948521984807'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/1957227948521984807'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2010/11/integration-testing-mail-function-with.html' title='Integration Testing Mail function with Greenmail and Spock in Grails'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-8217693170790520250</id><published>2010-10-28T16:14:00.003+01:00</published><updated>2010-10-29T14:25:08.316+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Hacking'/><category scheme='http://www.blogger.com/atom/ns#' term='test'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>When Run (Ctrl+F11) gets stuck in Eclipse.</title><content type='html'>In Eclipse (or its derivative Spring STS 2.5.0) generically, Ctrl+F11 is Run and it is context aware. As if the cursor is in a Java class with a main method, it will run the run class; if the cursor is in a test class, it will run the test class; if the cursor is at the method line in a test class, it will run the test for this single method.&lt;br /&gt;&lt;br /&gt;However, when a new Grails plugin is installed, or if you run "grails test-app -coverage" you will noticed from the console that:&amp;nbsp;$app/web-app/WEB-INF/classes directory is deleted. And when you Ctrl+F11 to run again, it will have the following exceptions:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Class not found uk.ac.lse.LockerRegisterServiceUnitTests&lt;br /&gt;java.lang.ClassNotFoundException: uk.ac.lse.LockerRegisterServiceUnitTests&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;at java.net.URLClassLoader$1.run(URLClassLoader.java:200)&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;at java.security.AccessController.doPrivileged(Native Method)&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;at java.net.URLClassLoader.findClass(URLClassLoader.java:188)&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;at java.lang.ClassLoader.loadClass(ClassLoader.java:307)&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;at java.lang.ClassLoader.loadClass(ClassLoader.java:252)&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.loadClass(RemoteTestRunner.java:693)&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.loadClasses(RemoteTestRunner.java:429)&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:452)&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Because the Default output folder is $app/web-app/WEB-INF/classes, that's why the test or run(main method for java) can't be run.&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To get your&amp;nbsp;favourite&amp;nbsp;Ctrl+F11 come back work for you, do the following:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;1. Delete the project without deleting the content from Eclipse.&lt;/div&gt;&lt;div&gt;2. Import your project into Eclipse.&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;/***** The following approach DOES NOT work ********/&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Or better (29/10/2010)&lt;br /&gt;&lt;br /&gt;1. Right click your project.&lt;br /&gt;2. Select Grails Tools -&amp;gt; Refresh Dependencies&lt;br /&gt;&lt;br /&gt;Then you will find the classes are compiled in to $app/target/classes which is the place your test or main java classes will run from.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-8217693170790520250?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/8217693170790520250/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=8217693170790520250' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/8217693170790520250'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/8217693170790520250'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2010/10/when-ctrlf11-get-stuck.html' title='When Run (Ctrl+F11) gets stuck in Eclipse.'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-2817286408278522492</id><published>2010-10-25T11:25:00.003+01:00</published><updated>2010-11-22T14:01:27.442Z</updated><title type='text'>Lockers App is Launched.</title><content type='html'>Very excited, my Online Locker Booking System will be launched today. It was built using Grails in 3 months.&lt;br /&gt;&lt;br /&gt;550+ lockers will be booked within 1 hour, then the waiting list is built up until it reaches its max limit.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-2817286408278522492?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/2817286408278522492/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=2817286408278522492' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/2817286408278522492'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/2817286408278522492'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2010/10/lockers-app-is-launched.html' title='Lockers App is Launched.'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-2806134212379194926</id><published>2010-08-02T10:36:00.102+01:00</published><updated>2010-08-02T11:46:35.437+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Grails Exception Handling with HTTP Status Code, URLMapping, and Email</title><content type='html'>The post describes how to:&lt;br /&gt;&lt;br /&gt;1. Configure the UrlMapping.groovy to allow custom action on the specific http status code. &lt;br /&gt;2. Display a customised "https status code handling page" to the user.&lt;br /&gt;3. Send customised "https status code handling page" as an email to the admin staff if the admin email is configured in the Config.groovy file.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;1. Configure the UrlMapping.groovy&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: groovy;"&gt;class UrlMappings {&lt;br /&gt;  static mappings {&lt;br /&gt;    "403" (controller: "error", action: "forbidden")&lt;br /&gt;    "404" (controller: "error", action: "notFound")&lt;br /&gt;    "500" (controller: "error", action: "internalError")&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;So any page status with 500 will be handled by the internalError action in the error controller. &lt;br /&gt;&lt;br /&gt;Individual exceptions can be also configured in the response code to give more fine grained level control&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: groovy;"&gt;"500" (controller: "error", action: "nullPointer", exception: NullPointerException)&lt;br /&gt;  "500" (controller: "error", action: "illegalArgument", exception: IllegalArgumentException)&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;This allows any NullPointerException with 500 http status code to be handled by nullPointer action of error controller. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;2. Display a customised "https status code handling page" to the user.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;There are two properties available to the exception handling page. These properties are: exception and request. So you can copy the default error.gsp in the grails-app/view folder to a new file which is specified in the UrlMapping.groovy (i.e. error/internalError.gsp) and modified it to your needs. &lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: html"&gt;...&lt;br /&gt;&lt;strong&gt;Error ${request.'javax.servlet.error.status_code'}:&lt;/strong&gt; ${request.'javax.servlet.error.message'.encodeAsHTML()}&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Servlet:&lt;/strong&gt; ${request.'javax.servlet.error.servlet_name'}&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;URI:&lt;/strong&gt; ${request.'javax.servlet.error.request_uri'}&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;g:if test="${exception}"&gt;&lt;br /&gt;  &lt;br /&gt;&lt;h2&gt;Stack Trace&lt;/h2&gt;&lt;div class="stack"&gt;&lt;pre&gt;&lt;g:each in="${exception.stackTraceLines}"&gt;${it.encodeAsHTML()}&lt;/g:each&gt;&lt;/pre&gt;&lt;/div&gt;...&lt;/g:if&gt;&lt;/pre&gt;&lt;br /&gt;The error page is as below:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_LMzsCH4-1v4/TFahnzZItVI/AAAAAAAAAn8/6yizVluDuyM/s1600/errorpage.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="457" src="http://4.bp.blogspot.com/_LMzsCH4-1v4/TFahnzZItVI/AAAAAAAAAn8/6yizVluDuyM/s640/errorpage.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;3. Send customised "https status code handling page" as an email to the admin staff&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;The grails mail plugin is required to fulfil this requirement. Please refer to the &lt;a href="http://www.grails.org/Mail+plugin"&gt;Grail Mail plugin&lt;/a&gt; documentation&lt;br /&gt;&lt;br /&gt;The following sending email code needs to be placed in the relevant action specified in the UrlMapping.groovy file. &lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: groovy;"&gt;import org.codehaus.groovy.grails.commons.ConfigurationHolder&lt;br /&gt;&lt;br /&gt;class ErrorController {&lt;br /&gt;&lt;br /&gt;  def mailService // mailService is provided by the grails mail plugin&lt;br /&gt; &lt;br /&gt;  def index = { }&lt;br /&gt;    &lt;br /&gt;  def internalError = {&lt;br /&gt;    // admin email is specified in the Config.groovy file&lt;br /&gt;    // An email will be sent to the admin person whenever an internalError occurred. &lt;br /&gt;    def adminEmail = ConfigurationHolder.config.admin.email &lt;br /&gt;    try {&lt;br /&gt;      mailService.sendMail {&lt;br /&gt; multipart true&lt;br /&gt; to adminEmail&lt;br /&gt; subject "500 Error"&lt;br /&gt; body (view: "/email/error")&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    catch (Exception e) {&lt;br /&gt;      log.info e&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;    &lt;br /&gt;  def notFound = {}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The exception and request properties in the exception handling page are also available in the email template page. Thus the default error.gsp can be also copied to email template page (i.e. grails-app/email/error.gsp) and modified to your needs.&lt;br /&gt;&lt;br /&gt;The&amp;nbsp;error&amp;nbsp;email is as below:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_LMzsCH4-1v4/TFah3FLD2mI/AAAAAAAAAoE/O4PyP-9EqyA/s1600/errorEmail.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="640" src="http://4.bp.blogspot.com/_LMzsCH4-1v4/TFah3FLD2mI/AAAAAAAAAoE/O4PyP-9EqyA/s640/errorEmail.jpg" width="608" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-2806134212379194926?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/2806134212379194926/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=2806134212379194926' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/2806134212379194926'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/2806134212379194926'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2010/08/grails-exception-handling-with-response.html' title='Grails Exception Handling with HTTP Status Code, URLMapping, and Email'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_LMzsCH4-1v4/TFahnzZItVI/AAAAAAAAAn8/6yizVluDuyM/s72-c/errorpage.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-8056975346259444999</id><published>2010-06-29T11:09:00.001+01:00</published><updated>2010-06-30T23:01:12.481+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='test'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>mockLogging in Grails Test</title><content type='html'>"By calling mockLogging(Class) in your unit test, any subsequently create instance of the given class will magically gain a working log property that echoes all log messages to the console. By default, debug and trace messages aren't included, to avoid excess output, but you can enable the debug messages by passing true as an optional second argument to mockLogging()." -- (Grails in Action)&lt;br /&gt;&lt;br /&gt;class JetService {&lt;br /&gt;&amp;nbsp;&amp;nbsp;def doSomthing() {&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;def a = "hello world"&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;log.debug a&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class JetServiceUnitTests extends grails.test.GrailsUnitTestCase {&lt;br /&gt;&amp;nbsp;&amp;nbsp;void &amp;nbsp;testDoSomething() {&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;mockLogging(JetService, true) // the second parameter "true" will output debug messages in the service method&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;...&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;When running the unit test:&lt;br /&gt;&lt;br /&gt;grails test-app unit:unit JetServiceUnit&lt;br /&gt;&lt;br /&gt;In the report, you can see the debug message is shown in the System.output&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-8056975346259444999?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/8056975346259444999/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=8056975346259444999' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/8056975346259444999'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/8056975346259444999'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2010/06/mocklogging-in-grails-test.html' title='mockLogging in Grails Test'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-9029592995970731983</id><published>2010-06-23T11:20:00.001+01:00</published><updated>2010-06-29T10:45:26.337+01:00</updated><title type='text'>shouldFail in Groovy Testing</title><content type='html'>If the program hasn't got code to catch the &lt;a href="http://java.sun.com/docs/books/tutorial/essential/exceptions/runtime.html"&gt;runtime unchecked exceptions&lt;/a&gt;, then shouldFail can be used during groovy testing.&amp;nbsp;&lt;a href="http://groovy.codehaus.org/Unit+Testing"&gt;http://groovy.codehaus.org/Unit+Testing&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;shouldFail() allows you to check that a particular lock of code &lt;b&gt;throws an exception&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;shouldFail (NullPointerException) {&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;testService.methodA('xxx')&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;However runtime unchecked exceptions can sometimes be considered as bugs in the programme and should be dealt with.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-9029592995970731983?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/9029592995970731983/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=9029592995970731983' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/9029592995970731983'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/9029592995970731983'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2010/06/shouldfail-in-groovy-testing.html' title='shouldFail in Groovy Testing'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-3071183523553900205</id><published>2010-06-07T17:25:00.001+01:00</published><updated>2010-06-07T17:25:59.831+01:00</updated><title type='text'>Grails Controller Unit Test</title><content type='html'>import grails.converters.JSON&lt;br /&gt;&lt;br /&gt;class PersonController {&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;def personService&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;def jsonPeople = {&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;def people = personService.getPerson('usrname', 'passwd')&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;render people as JSON&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;class PersonService {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;static transactional = true&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;def getPerson(String usrname, String password) {&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;// some business logic&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;return [firstname: 'joe', lastname: 'blog']&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;import grails.test.*&lt;br /&gt;import grails.converters.JSON&lt;br /&gt;&lt;br /&gt;class PersonControllerTests extends ControllerUnitTestCase {&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;protected void setUp() {&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;  &lt;/span&gt;super.setUp()&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;}&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;protected void tearDown() {&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;  &lt;/span&gt;super.tearDown()&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;}&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;void testJsonResponse() {&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;  &lt;/span&gt;controller.params.username= 'usrname'&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;  &lt;/span&gt;controller.params.password = 'passwd'&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;// mock the colloaborator&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;  &lt;/span&gt;def personControl = mockFor(PersonService)&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;  &lt;/span&gt;personControl.demand.getPerson(1..1) { String x, String y -&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;// the number of parameters and return type have to match the method&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;   &lt;/span&gt;return [firstname: 'joe', lastname: 'blog']&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;  &lt;/span&gt;}&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;  &lt;/span&gt;controller.personService = personControl.createMock()&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;  &lt;/span&gt;controller.jsonPeople()&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;  &lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;  &lt;/span&gt;//parse the JSON&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;  &lt;/span&gt;def controllerResponse = controller.response.contentAsString&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;  &lt;/span&gt;def jsonResult = JSON.parse(controllerResponse)&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;  &lt;/span&gt;//navigate the JSON as an object&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;  &lt;/span&gt;assertEquals 'joe', jsonResult.username&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;  &lt;/span&gt;assertEquals 'blog', jsonResult.password&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;  &lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-3071183523553900205?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/3071183523553900205/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=3071183523553900205' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/3071183523553900205'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/3071183523553900205'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2010/06/grails-controller-unit-test.html' title='Grails Controller Unit Test'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-139276824217175716</id><published>2010-05-21T10:37:00.003+01:00</published><updated>2011-05-05T16:02:53.335+01:00</updated><title type='text'>JMeter HTTP Proxy Server Settings</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: left;"&gt;The procedures below shows how to set up a HTTP proxy server using JMeter together with Firefox.&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;At WorkBench, add a HTTP Proxy Server.&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_LMzsCH4-1v4/S_ZOzpXPWBI/AAAAAAAAAnA/2rIrc_TfS-M/s1600/JMeter+Add+HTTP+Proxy+Server.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="105" src="http://2.bp.blogspot.com/_LMzsCH4-1v4/S_ZOzpXPWBI/AAAAAAAAAnA/2rIrc_TfS-M/s400/JMeter+Add+HTTP+Proxy+Server.JPG" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;In the newly added HTTP Proxy Server control panel.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Add "text/html" in the Content-type filter include field, so that all the html format page request will be filtered in.&lt;/li&gt;&lt;li&gt;In the URL Patterns to Exclude, add&amp;nbsp;.*\.jpg &amp;nbsp;.*\.js &amp;nbsp;.*\.png &amp;nbsp;.*\.gif &amp;nbsp;.*\.css&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;The url request containing these extension will not shown on the JMeter left&amp;nbsp;panel, as we are not interested in requesting these files for our testing purpose.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;optional&gt; Change "port" to 8090, if your application is running under 8080&lt;/optional&gt;&lt;/li&gt;&lt;li&gt;Click Start to start the proxy server.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_LMzsCH4-1v4/S_ZRAe-SjsI/AAAAAAAAAnI/S5F1TM9_2d0/s1600/JMeter+HTTP+Proxy+Server.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="483" src="http://4.bp.blogspot.com/_LMzsCH4-1v4/S_ZRAe-SjsI/AAAAAAAAAnI/S5F1TM9_2d0/s640/JMeter+HTTP+Proxy+Server.JPG" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Launch Firefox, in the Tools -&amp;gt; Options -&amp;gt; Network&amp;nbsp;-&amp;gt;&amp;nbsp;Settings, set the Manual proxy configuration to:&lt;br /&gt;HTTP Proxy: localhost&lt;br /&gt;Port: 8090 (this should be the same as the setting in the JMeter HTTP Proxy Server setting)&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_LMzsCH4-1v4/S_ZSMupa9LI/AAAAAAAAAnQ/LTyD2sGAPGo/s1600/Firefox+Proxy+Server+Setting.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="400" src="http://1.bp.blogspot.com/_LMzsCH4-1v4/S_ZSMupa9LI/AAAAAAAAAnQ/LTyD2sGAPGo/s400/Firefox+Proxy+Server+Setting.JPG" width="308" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Now type any web address in Firefox, you will see only those url (e.g. /myApp/myController/index) request interested to us will come through in the left panel of the JMeter.&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;If there are other url &amp;nbsp;request which are not interested to us, then simply add their url patterns to the URL Patterns to Exclude section in the HTTP Proxy Server settings in the JMeter.&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;p.s. remember to put port 80 in the port field in HttpRequest Client&lt;/div&gt;&lt;br /&gt;There are video resources which give introductions on JMeter:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://vimeo.com/10164982"&gt;http://vimeo.com/10164982&lt;/a&gt;&lt;br /&gt;&lt;a href="http://vimeo.com/3453772"&gt;http://vimeo.com/3453772&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-139276824217175716?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/139276824217175716/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=139276824217175716' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/139276824217175716'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/139276824217175716'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2010/05/jmeter-http-proxy-server-settings.html' title='JMeter HTTP Proxy Server Settings'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_LMzsCH4-1v4/S_ZOzpXPWBI/AAAAAAAAAnA/2rIrc_TfS-M/s72-c/JMeter+Add+HTTP+Proxy+Server.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-1989919484421102449</id><published>2010-04-29T15:17:00.001+01:00</published><updated>2010-09-01T15:29:50.384+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Convert GroovyRowResult into Domain Class</title><content type='html'>There are chances that you might want to convert a GroovyRowResult into a domain class. For example, in the clustered environment, certain class needs to "implments Serializable" but if there is GroovyRowResult is in the class, then it will throw&amp;nbsp;&amp;nbsp;java.io.NotSerializableException&amp;nbsp;as GroovyRowResult can not be serialized.&lt;br /&gt;&lt;br /&gt;The workaround is simply create a dummy domain class with properties match the result set fields. It is case sensitive. &lt;br /&gt;&lt;br /&gt;If it is oracle database, then it is case sensitive. &lt;br /&gt;&lt;br /&gt;GroovyRowResult row = connection.firstRow("select user.firstname as \"firstname\"......")&lt;br /&gt;def person = new Peson (row)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-1989919484421102449?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/1989919484421102449/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=1989919484421102449' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/1989919484421102449'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/1989919484421102449'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2010/04/convert-groovyrowresult-into-domain.html' title='Convert GroovyRowResult into Domain Class'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-424005430492680041</id><published>2010-04-19T10:51:00.000+01:00</published><updated>2010-04-19T10:51:49.846+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>Number format</title><content type='html'>When comes to custom number formatting, you might have a user case like room number 001, 075. How to format this:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;NumberFormat formatter = new DecimalFormat("000")&lt;br /&gt;def s &lt;br /&gt;s = formatter.format(1) // the result will be 001&lt;br /&gt;s = formatter.format(75) // the result will be 075&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-424005430492680041?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/424005430492680041/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=424005430492680041' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/424005430492680041'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/424005430492680041'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2010/04/number-format.html' title='Number format'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-7654741400072521168</id><published>2010-03-15T10:26:00.002Z</published><updated>2010-03-15T10:26:34.375Z</updated><title type='text'>current is a reserved word for Grails</title><content type='html'>&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-7654741400072521168?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/7654741400072521168/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=7654741400072521168' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/7654741400072521168'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/7654741400072521168'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2010/03/current-is-reserved-word-for-grails.html' title='current is a reserved word for Grails'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-713895756615703196</id><published>2009-12-10T22:32:00.003Z</published><updated>2009-12-11T10:42:32.703Z</updated><title type='text'>Groovy/Grails Exchange London 2009</title><content type='html'>Just attended the &lt;a href="http://skillsmatter.com/event/java-jee/groovy-grails-exchange-2009/wd-184"&gt;Groovy/Grails Exchange London 2009 conference&lt;/a&gt;. Podcast and slides can be found there as well. &lt;br /&gt;&lt;br /&gt;SkillsMatter uploaded &lt;a href="http://groovy-grails-exchange.ning.com/photo/photo"&gt;more photos&lt;/a&gt;. I am in the picture (sitting very front) ;)&lt;br /&gt; &lt;br /&gt;It is a festival for those enthusiastic groovy/grails lovers to learn new things and exchange knowledge and practice. &lt;br /&gt;&lt;br /&gt;Got quite quite a few point to take away into practice.&lt;br /&gt;&lt;br /&gt;Guillaume LaForge introduced new features of Groovy 1.7. Try it out. &lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.grails.org/plugin/iwebkit"&gt;iWebKit&lt;/a&gt;, the mobile plugin for grails, is a must playing one when off work. &lt;br /&gt;&lt;br /&gt;Burt Beckwith, the &lt;a href="http://grails.org/plugin/acegi"&gt;Spring Security (aka acegi) plugin&lt;/a&gt; developer, took the grails application into an enterprise level - Clustering a Grails Application for Scalability and Availability and t&lt;br /&gt;&lt;br /&gt;Venkat Subramaniam is the live coding ninja. His presentation and demo style is just fantastic. The pace of his talk is like prison break season 1 -- I want to know what is coming next. Following his way, you increase your job security. &lt;br /&gt;&lt;br /&gt;Christian Dupuis from SpringSource demonstrated the &lt;a href="http://www.springsource.com/products/sts"&gt;Groovy/Grails plugin for Eclipse&lt;/a&gt;. I can see lots of improvement which had been made, but there are still lots of features lacking. I am a Eclipse lover. Come one, Let's wave the Eclipse flag. &lt;br /&gt;&lt;br /&gt;Graeme Rocher talked about cloud, plugin systems and &lt;a href="http://www.grails.org/1.2-RC1+Release+Notes"&gt;Grails 1.2 new features&lt;/a&gt;. Just try it. &lt;br /&gt;&lt;br /&gt;Tomas Lin demonstrated how to use flex as a front end to talk to grails. Brilliant.&lt;br /&gt;&lt;br /&gt;Well, so many things to take on to digest. Looking forward to the &lt;a href="http://qconlondon.com/"&gt;QCon London 2010&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Groovy/Grails have a bright future for Java developers.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-713895756615703196?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/713895756615703196/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=713895756615703196' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/713895756615703196'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/713895756615703196'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2009/12/groovygrails-exchange-london-2009.html' title='Groovy/Grails Exchange London 2009'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-1746739053844319716</id><published>2009-09-16T10:51:00.006+01:00</published><updated>2009-12-10T01:13:30.486Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Regular Expression'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>Java Regular Expression Experience.</title><content type='html'>If the input only allows the number format like the following: 1, 11, 1.1, 1.11, 11.1, 11.11. &lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class Test {&lt;br /&gt;  java.math.BigDecimal price&lt;br /&gt;&lt;br /&gt;  static constraints = {&lt;br /&gt;    price(blank: false, validator: {val, obj -&gt;&lt;br /&gt;      // this will only allow those 33.33 format&lt;br /&gt;      if (!Pattern.matches("\\d{0,2}\\.\\d{0,2}", val.toString())&lt;br /&gt;        &amp;&amp; !Pattern.matches("\\d{0,2}", val.toString())) {&lt;br /&gt;        return ['digital']&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    )&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Please refer to &lt;a href="http://java.sun.com/javase/6/docs/api/java/util/regex/Pattern.html"&gt;Java Regular Expression docs&lt;/a&gt; for more info.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;In addition, make sure the mysql table column price with the right (enough) type: decimal (10, 2).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-1746739053844319716?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/1746739053844319716/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=1746739053844319716' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/1746739053844319716'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/1746739053844319716'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2009/09/java-regular-expression-experience.html' title='Java Regular Expression Experience.'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-8047777263024269326</id><published>2009-09-15T12:47:00.005+01:00</published><updated>2009-09-15T14:29:25.992+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Calendar datepicker Plugin in Grails</title><content type='html'>Refer to &lt;a href="http://grails.org/plugin/calendar"&gt;Grails Calendar Plugin site&lt;/a&gt; for how to install and use the plugin.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;g:form&amp;gt;&lt;br /&gt;&amp;lt;calendar:datePicker name="myDate" defaultValue="${new Date()}" dateFormat="%d/%m/%Y"/&amp;gt;&lt;br /&gt;&amp;lt;g:actionSubmit name="myAction" value=Submit"/&amp;gt; &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;There will be some html and javascript code generated by the plugin when viewing page source. The code we care is:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;...&lt;br /&gt;&amp;lt;input type="text" id="myDate_value" name="myDate_value" readonly="true"/&amp;gt;&lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The submitted myDate will be in String format dd/mm/YYYY, and we will use myDate_value in our controller to retrieve value.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class MyController {&lt;br /&gt;    def myAction = {&lt;br /&gt;        if (params['myDate_value'] != null) {&lt;br /&gt;            def f = new SimpleDateFormat("dd/MM/yyyy")&lt;br /&gt;            def myDate = f.parse(params['myDate_value'])&lt;br /&gt;&lt;br /&gt;            // Testing&lt;br /&gt;            println myDate.class // it is java.util.Date&lt;br /&gt;            println myDate // Tue Sep 15 00:00:00 BST 2009&lt;br /&gt;&lt;br /&gt;            def test = Test.get(1)&lt;br /&gt;            println test.dateCreated.class //java.sql.Timestamp&lt;br /&gt;            println test.dateCreated  // 2009-09-14 10:34:10.0&lt;br /&gt;&lt;br /&gt;            // Time comparison&lt;br /&gt;            println myDate &gt; test.dateCreated   // true&lt;br /&gt;            println myDate == test.dateCreated    // false&lt;br /&gt;            println myDate &lt; test.dateCreated    // false &lt;br /&gt;            ....&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-8047777263024269326?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/8047777263024269326/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=8047777263024269326' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/8047777263024269326'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/8047777263024269326'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2009/09/calendar-datepicker-plugin-in-grails.html' title='Calendar datepicker Plugin in Grails'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-5297085165536926194</id><published>2009-09-15T12:23:00.005+01:00</published><updated>2009-09-15T12:39:43.403+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'></title><content type='html'>The unique constraint in Grails works fine out of the box when the field is not a primary key. But it cause exceptions if the field is a manually assigned primary key. &lt;br /&gt;Also refer to Grails doc for unique constraint. &lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class Test&lt;br /&gt;  String id&lt;br /&gt;&lt;br /&gt;  static mapping = {&lt;br /&gt;    table 'test'&lt;br /&gt;    id generator:'assigned', column:'id'  &lt;br /&gt;  }&lt;br /&gt;static constraints = {&lt;br /&gt;  id(blank: false, unique: true)&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Exception will be thrown when saving it with a duplicate id. &lt;br /&gt;&lt;br /&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 302px;" src="http://2.bp.blogspot.com/_LMzsCH4-1v4/Sq98tqM-T3I/AAAAAAAAAdg/xqHokY4WTO4/s400/unique.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5381657203595693938" /&gt;&lt;br /&gt;&lt;br /&gt;The solution is as below:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class TestController {&lt;br /&gt;  def save = {&lt;br /&gt;    def testInstance = new Test(params)&lt;br /&gt;       try {&lt;br /&gt;        if(!testInstance.hasErrors() &amp;&amp; testInstance.save()) {&lt;br /&gt;            flash.message = "Test ${testInstance.id} created"&lt;br /&gt;            redirect(action:show,id:courseInstance.id)&lt;br /&gt;        }&lt;br /&gt;        else {&lt;br /&gt;            render(view:'create',model:[testInstance:testInstance])&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;       catch (org.springframework.orm.hibernate3.HibernateSystemException e){&lt;br /&gt;           // Field in view to highlight using &lt;g:hasErrors&gt; tag&lt;br /&gt;           testInstance.errors.rejectValue('id', 'test.id.notUnique')                                                 &lt;br /&gt;           render(view:'create',model:[testInstance:testInstance])&lt;br /&gt;       }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In the message.properties file, add one entry:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;test.id.notUnique=The system has already had a id as you entered. Please provide a unique id.&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-5297085165536926194?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/5297085165536926194/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=5297085165536926194' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/5297085165536926194'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/5297085165536926194'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2009/09/unique-constraint-in-grails-works-fine.html' title=''/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_LMzsCH4-1v4/Sq98tqM-T3I/AAAAAAAAAdg/xqHokY4WTO4/s72-c/unique.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-2179389616959022382</id><published>2009-09-15T11:44:00.004+01:00</published><updated>2009-09-15T12:23:05.113+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='servlet'/><title type='text'>Remove Cookie in Servlet</title><content type='html'>In Firefox, view the cookie info via Web Developer plugin. Make sure the path is correct, that is where the cookie located. &lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px; height: 142px;" src="http://1.bp.blogspot.com/_LMzsCH4-1v4/Sq9xha7OPAI/AAAAAAAAAdQ/FdMNpGuqQZA/s320/cookie.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5381644898708372482" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;In Servlet, to remove a named cookie do: &lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Cookie myCookie = new Cookie("JSESSIONID", "");&lt;br /&gt;myCookie.setMaxAge(0);&lt;br /&gt;myCookie.setPath("/");&lt;br /&gt;//myCookie.setPath("/" + grailsApplication.metadata['app.name']);&lt;br /&gt;response.addCookie(myCookie);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Refer to the &lt;a href="http://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/servlet/http/Cookie.html#setMaxAge(int)"&gt;Java Servlet Cookie doc&lt;/a&gt;, set the MaxAge to 0 will delete the cookie.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-2179389616959022382?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/2179389616959022382/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=2179389616959022382' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/2179389616959022382'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/2179389616959022382'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2009/09/remove-cookie-in-servlet.html' title='Remove Cookie in Servlet'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_LMzsCH4-1v4/Sq9xha7OPAI/AAAAAAAAAdQ/FdMNpGuqQZA/s72-c/cookie.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-1383427249944657323</id><published>2009-08-14T16:25:00.003+01:00</published><updated>2009-08-14T18:20:27.004+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Database Result to Groovy List, Map</title><content type='html'>Person --* Order --* LineItem *-- Product&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;def lineItemList = LineItem.findAll()&lt;br /&gt;def t = []&lt;br /&gt;def q = []&lt;br /&gt;def lineItemMap = []&lt;br /&gt;def orderMap = []&lt;br /&gt;def packs&lt;br /&gt;lineItemList.order.person.unique().each { person -&gt;&lt;br /&gt;    def p = []&lt;br /&gt;    orders = lineItemList.findAll{it.order.person == person}.order&lt;br /&gt;    orders.unique().each { order -&gt;&lt;br /&gt;           lineItemMap = lineItemList.findAll{it.order == order}&lt;br /&gt;           orderMap = [orderId: order.id, lineItemId: lineItemMap.id]&lt;br /&gt;           p.add(orderMap)&lt;br /&gt;           // Use the statement below to get all the products&lt;br /&gt;           //products = LineItem.getAll(lineItemMap.id).product&lt;br /&gt;    }&lt;br /&gt;    q = [personId: person.id, order: p]&lt;br /&gt;    t.add(q)&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;[[personId:1, order:[[orderId:1, lineItemId:[1, 2]], [orderId:2, lineItemId:[3, 4]]]]]&lt;br /&gt;&lt;br /&gt;[[personId:1, order:[[orderId:1, lineItemId:[1, 2]]]], [personId:2, order:[[orderId:2, lineItemId:[3, 4]]]]]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-1383427249944657323?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/1383427249944657323/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=1383427249944657323' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/1383427249944657323'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/1383427249944657323'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2009/08/database-result-to-groovy-list-map.html' title='Database Result to Groovy List, Map'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-794676220073509771</id><published>2009-08-06T17:21:00.003+01:00</published><updated>2009-08-06T17:27:46.299+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Domain Class (Primary Key) Update and Table Generation</title><content type='html'>If you set dbCreate = "update" in the DataSource.groovy, then every time you change the domain class, the grails will update the table for you. Sometimes if it doesn't (the primary key (strategy) is changed), then drop the table, and restart the grails application. And it will reflect the changes in the domain class.&lt;br /&gt;&lt;br /&gt;To use a manually assigned value as a primary key rather than the default auto_increment one, do:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class Person {&lt;br /&gt;  String id&lt;br /&gt;  &lt;br /&gt;  static mapping = {&lt;br /&gt;    id generator: 'assigned', column: 'id'&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-794676220073509771?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/794676220073509771/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=794676220073509771' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/794676220073509771'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/794676220073509771'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2009/08/domain-class-update-and-table.html' title='Domain Class (Primary Key) Update and Table Generation'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-4524632718815231901</id><published>2009-08-03T10:49:00.007+01:00</published><updated>2009-08-04T16:56:42.829+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='servlet'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>List (array) of parameter values</title><content type='html'>Sometimes in a web form, it is useful to allow inputting multiple values to be associated with one&lt;br /&gt;&lt;br /&gt;In some scenarios, a web form can allow inputting multiple values to be associated with the same named field:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;form&amp;gt;&lt;br /&gt;&amp;lt;input name="key" type="text"&amp;gt;&lt;br /&gt;&amp;lt;input name="key" type="text"&amp;gt;&lt;br /&gt;&amp;lt;/form&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The posted url is like: ?key=value1&amp;amp;key=value2&lt;br /&gt;&lt;br /&gt;In Grails, params['key'] is always used to get parameter value. The default behaviour will return:&lt;br /&gt;&lt;br /&gt;a string if the key only has one value (i.e. ?key=value)&lt;br /&gt;a List if the key has many values (i.e. ?key=value1&amp;amp;key=value2)&lt;br /&gt;&lt;br /&gt;It causes problems when you are not sure how many values the key is associated with.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Solutions:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;In Java Servlet API, there is a method for Interface ServletRequest&lt;br /&gt;&lt;br /&gt;java.lang.String[] request getParameterValues(java.lang.String name)&lt;br /&gt;&lt;br /&gt;Returns an array of String objects containing all of the values the given request parameter has, or null if the parameter does not exist.&lt;br /&gt;&lt;br /&gt;request.getParameterValues('key')&lt;br /&gt;class [Ljava.lang.String;&lt;br /&gt;&lt;br /&gt;According to &lt;a href="http://groovy.codehaus.org/JN1025-Arrays"&gt;http://groovy.codehaus.org/JN1025-Arrays&lt;/a&gt;, we can use the following code to reconstruct the query string:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;def queryArray = request.getParameterValues('key')&lt;br /&gt;def queryString = ""&lt;br /&gt;queryArray.each {&lt;br /&gt;queryString += "&amp;amp;key=$it"&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;For the query string like: http://blabla.com/list?personId=1&amp;personId=2&lt;br /&gt;&lt;br /&gt;To accommodate this, in Grails scaffolded list closure:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;def list = {&lt;br /&gt;  def personList&lt;br /&gt;  if (params['personId'] != null) {&lt;br /&gt;     personList = Person.getAll(Arrays.asList(request.getParameterValues('personId')))&lt;br /&gt;  }&lt;br /&gt;  else {&lt;br /&gt;     personList = Person.list()&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;To cast an array into a list, using:&lt;br /&gt;&lt;br /&gt;Arrays.asList(array[])&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Also refer to &lt;a href="http://prideafrica.blogspot.com/2007/01/javalangclasscastexception.html"&gt;http://prideafrica.blogspot.com/2007/01/javalangclasscastexception.html&lt;/a&gt; for some useful info regarding &lt;b&gt;[Ljava.lang.String&lt;/b&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-4524632718815231901?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/4524632718815231901/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=4524632718815231901' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/4524632718815231901'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/4524632718815231901'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2009/08/list-array-of-parameter-values.html' title='List (array) of parameter values'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-9183854257178715067</id><published>2009-07-29T10:50:00.003+01:00</published><updated>2009-07-29T11:00:57.027+01:00</updated><title type='text'>GORM Lazy</title><content type='html'>If we have the domain relations (one Order has many Items, and one Item can appear in many Orders) modelled below:&lt;br /&gt;&lt;br /&gt;Order --* LineItem *-- Item&lt;br /&gt;&lt;br /&gt;If we want the toString() method of the LineItem class to return its relation classes attributes, then that's where lazy strategy comes in handy.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class LineItem {&lt;br /&gt;&lt;br /&gt;  // relation&lt;br /&gt;  Order order&lt;br /&gt;  Item item&lt;br /&gt;&lt;br /&gt;  static mapping = {&lt;br /&gt;    columns {&lt;br /&gt;       order lazy: false&lt;br /&gt;       item lazy: false&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  String toString() {&lt;br /&gt;    return "Order no: $this.order.id, Item: $this.item.name"&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-9183854257178715067?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/9183854257178715067/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=9183854257178715067' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/9183854257178715067'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/9183854257178715067'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2009/07/gorm-lazy.html' title='GORM Lazy'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-3420714942085449671</id><published>2009-07-21T10:46:00.004+01:00</published><updated>2009-07-21T10:59:04.588+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Get Session in Grails Service</title><content type='html'>In Grails, session variable is not available in service. But &lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import org.springframework.web.context.request.RequestContextHolder&lt;br /&gt;&lt;br /&gt;def user = RequestContextHolder.currentRequestAttributes().getSession()?.user&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Note: the RequestContextHolder is genuinely a normal web request. If the request is a scheduled job (using Quartz plutin), not a web request, then there will be exceptions like below: &lt;br /&gt;&lt;pre&gt;&lt;br /&gt;=============================&lt;br /&gt;2009-07-21 00:00:00,269 INFO  [core.JobRunShell] Job GRAILS_JOBS.ExpireJob threw a JobExecutionException:&lt;br /&gt;org.quartz.JobExecutionException: No thread-bound request found: Are you referring to request attributes outside of an actual&lt;br /&gt; web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web&lt;br /&gt;request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this&lt;br /&gt; case, use RequestContextListener or RequestContextFilter to expose the current request. [See nested exception: java.lang.Ill&lt;br /&gt;egalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request,&lt;br /&gt;or processing a request outside of the originally receiving thread? If you are actually operating within a web request and st&lt;br /&gt;ill receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use Req&lt;br /&gt;uestContextListener or RequestContextFilter to expose the current request.]&lt;br /&gt;        at org.codehaus.groovy.grails.plugins.quartz.GrailsJobFactory$GrailsTaskClassJob.execute(GrailsJobFactory.java:81)&lt;br /&gt;        at org.quartz.core.JobRunShell.run(JobRunShell.java:202)&lt;br /&gt;        at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:525)&lt;br /&gt;Caused by: java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of&lt;br /&gt; an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating wit&lt;br /&gt;hin a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortle&lt;br /&gt;t: In this case, use RequestContextListener or RequestContextFilter to expose the current request.&lt;br /&gt;        at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:12&lt;br /&gt;2)&lt;br /&gt;        at org.springframework.web.context.request.RequestContextHolder$currentRequestAttributes.call(Unknown Source)&lt;br /&gt;        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:43)&lt;br /&gt;        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)&lt;br /&gt;        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:120)&lt;br /&gt;        at EmailerService.sendEmails(EmailerService.groovy:64)&lt;br /&gt;        at EmailerService$sendEmails$0.call(Unknown Source)&lt;br /&gt;        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:43)&lt;br /&gt;        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)&lt;br /&gt;        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:124)&lt;br /&gt;        at ExpireJob$_execute_closure1.doCall(ExpireJob.groovy:38)&lt;br /&gt;        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)&lt;br /&gt;        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)&lt;br /&gt;        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)&lt;br /&gt;        at java.lang.reflect.Method.invoke(Method.java:597)&lt;br /&gt;        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86)&lt;br /&gt;        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:234)&lt;br /&gt;        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1061)&lt;br /&gt;        at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:910)&lt;br /&gt;        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:892)&lt;br /&gt;        at groovy.lang.Closure.call(Closure.java:279)&lt;br /&gt;        at groovy.lang.Closure.call(Closure.java:292)&lt;br /&gt;        at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:1165)&lt;br /&gt;        at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:1141)&lt;br /&gt;        at org.codehaus.groovy.runtime.dgm$87.invoke(Unknown Source)&lt;br /&gt;        at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoMetaMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSi&lt;br /&gt;te.java:270)&lt;br /&gt;        at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:52)&lt;br /&gt;============================&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If you are logging this scheduled job, then do:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    try {&lt;br /&gt;      def user = RequestContextHolder.currentRequestAttributes().getSession()?.user&lt;br /&gt;      if (user != null) {&lt;br /&gt;        log.info("Email: ${mail.dump()}, action: sendEmails by ${user} on ${new Date()}")&lt;br /&gt;      }&lt;br /&gt;      else {&lt;br /&gt;        log.info("Email: ${mail.dump()}, action: sendEmails by system on ${new Date()}")&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    catch (java.lang.IllegalStateException e) {&lt;br /&gt;      log.info("Email: ${mail.dump()}, action: sendEmails by system on ${new Date()}")&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-3420714942085449671?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/3420714942085449671/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=3420714942085449671' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/3420714942085449671'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/3420714942085449671'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2009/07/get-session-in-service.html' title='Get Session in Grails Service'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-1751068761774970320</id><published>2009-07-03T15:07:00.001+01:00</published><updated>2009-07-03T15:09:37.604+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MySQL'/><title type='text'>Select Column Name with Space</title><content type='html'>If the column name has space in it, then use backtick operator like this `column name`&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-1751068761774970320?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/1751068761774970320/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=1751068761774970320' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/1751068761774970320'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/1751068761774970320'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2009/07/select-column-name-with-space.html' title='Select Column Name with Space'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-6647347455775727123</id><published>2009-07-03T12:25:00.023+01:00</published><updated>2009-07-10T11:54:59.585+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MySQL'/><category scheme='http://www.blogger.com/atom/ns#' term='Access'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Migrate Access to MySQL to Fit in Grails</title><content type='html'>&lt;div style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="font-weight: bold; "&gt;1. Access Tables Preparation&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;div&gt;Open the Access database and modify the table names and column names with the following convention:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Modify the table names to table_name (e.g. account_manager) format if necessary. GRAG will generate a domain class named: TableName.&lt;/li&gt;&lt;li&gt;Modify column names to column_name (e.g. contact_address) format if necessary. GRAG will generate a field named: columnName.&lt;/li&gt;&lt;li&gt;Create an autoNumber id as the primary key if the table doesn't have one&lt;/li&gt;&lt;li&gt;If the table's primary key is not named id, then change it to id. GRAG will generate an id field with the mapping like: id generator:'identity', column:'id'&lt;/li&gt;&lt;li&gt;Modify foreign keys in other tables as table_name_id. GRAG will create a relation for this.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;span class="Apple-style-span" style="font-weight: bold; "&gt;2. Migrate Access to MySQL&lt;br /&gt;&lt;/span&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;MySQL Migration Toolkit to migrate MS Access to MySQL (h&lt;a href="ttp://dev.mysql.com/downloads/gui-tools/5.0.html"&gt;ttp://dev.mysql.com/downloads/gui-tools/5.0.html&lt;/a&gt;). It is an automatic process with step by step instructions. The tool will generate dbCreate.sql and dbInserts.sql, remember to save them. Then: &lt;div&gt;&lt;ul&gt;&lt;li&gt;Modify the dbCreate.sql to add foreign keys which GRAG will create relations for the generated domain class, and add version int(10) field, otherwise a 'version false' statement will be generated in the mapping, because this isn't available by default for legacy databases&lt;/li&gt;&lt;li&gt;Re run the dbCreate.sql script to re-generate the tables. &lt;/li&gt;&lt;li&gt;Re run the dbInserts.sql script to populate the data.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;3. Generate the Domain Classes&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Then you can start using Grails Application Generator (GRAG) (&lt;a href="ttp://dev.mysql.com/downloads/gui-tools/5.0.html"&gt;http://grag.sourceforge.net/&lt;/a&gt;) to generate the domain models. It is not perfect, but at least it saves some manul typings.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Open the generated domain classes to:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;check the generated field to see wheter it comforms to the lowerCaseCapital format (e.g. contactAddress)&lt;/li&gt;&lt;li&gt;If the id is an auto_increment field, then comment out the id field, and comment out &lt;span class="Apple-style-span" style="font-weight: bold; "&gt;id generator:'identity', column:'id' &lt;/span&gt;statement.&lt;/li&gt;&lt;li&gt;If the id is a user assigned value field (e.g. characters), then don't comment out the id field. Also, change the &lt;b&gt;id generator&lt;/b&gt; in the mapping to: &lt;b&gt;id generator:'assigned', column:'id'&lt;/b&gt;&lt;/li&gt;&lt;li&gt;modify relations if necessary (i.e. hasMany, belongsTo, or association like: OtherDomain otherDomain)&lt;/li&gt;&lt;li&gt;comment out constraint for a start&lt;/li&gt;&lt;li&gt;modify the toString method to return some meaningful value.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;4. Configuration&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;Change dbCreate to 'update' in the DataSource.groovy so that the data&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;5. Testing&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;runt he "grails console", then for each domain class, test it with the following script:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;def a = DomainClass.get('KK')&lt;/div&gt;&lt;div&gt;a.dump()&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;6. Generate Skeletons Code&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;grails generate-all *&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This will generate the controllers and gsp view pages for all the domain classes.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;7. Modify assigned id field for controller and gsp&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If the id is a user assigned id rather than an auto incremented id, then for the controller, explicitly assign the id: &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;div style="clear:both"&gt; &lt;br /&gt;&lt;pre&gt;&lt;br /&gt;def save = {&lt;br /&gt;    def nameInstance = new Name(params)&lt;br /&gt;    &lt;b&gt;nameInstance.id = params.id&lt;/b&gt;&lt;br /&gt;    if(! nameInstance.hasErrors() &amp;amp;&amp;amp; nameInstance.save()) {&lt;br /&gt;       ...&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;For the create.gsp page, add the id input field:&lt;br /&gt;&lt;div style="clear:both"&gt;&lt;br /&gt;&lt;pre&gt;            &lt;br /&gt;&amp;lt;tr class='prop'&amp;gt;&lt;br /&gt; &amp;lt;td valign='top' style='text-align:left;' width='20%'&amp;gt;&lt;br /&gt;      &amp;lt;label for='id'&amp;gt;ID:&amp;lt;/label&amp;gt;&lt;br /&gt; &amp;lt;/td&amp;gt;&lt;br /&gt; &amp;lt;td valign='top' style='text-align:left;' width='80%'&lt;br /&gt;class='${hasErrors(bean:nameInstance,field:'id','errors')}'&amp;gt;&lt;br /&gt; &amp;lt;input type='text' name='id' value='${nameInstance?.id}' /&amp;gt;&lt;br /&gt; &amp;lt;/td&amp;gt;&lt;br /&gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;There is also a very good post regarding &lt;a href="http://jasonrudolph.com/blog/2006/06/20/hoisting-grails-to-your-legacy-db/"&gt;Hosting Grails to your Legacy Database&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-6647347455775727123?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/6647347455775727123/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=6647347455775727123' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/6647347455775727123'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/6647347455775727123'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2009/07/mysql-migration-toolkit.html' title='Migrate Access to MySQL to Fit in Grails'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-6691072136244448966</id><published>2009-06-30T16:08:00.012+01:00</published><updated>2009-07-01T17:08:11.498+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Digesting belongsTo</title><content type='html'>&lt;pre&gt;&lt;br /&gt;class Face {&lt;br /&gt;String name&lt;br /&gt;Nose nose&lt;br /&gt;static constraints = {&lt;br /&gt;nose (nullable: true)&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;String toString() {&lt;br /&gt;return name &lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class Nose {&lt;br /&gt;String name&lt;br /&gt;static belongsTo = [face: Face]&lt;br /&gt;String toString() {&lt;br /&gt;return name &lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;def a = new Face(name: 'joe')&lt;br /&gt;def b = new Nose(name: 'blog')&lt;br /&gt;a.b = b&lt;br /&gt;a.save(flush: true)&lt;br /&gt;b.save(flush: true)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;// test&lt;br /&gt;def face = Face.findWhere (name: 'joe')&lt;br /&gt;println face.nose&lt;br /&gt;&lt;br /&gt;def nose = Nose.findWhere(name: 'blog')&lt;br /&gt;println nose.face&lt;br /&gt;&lt;br /&gt;// You must set nullable: true for nose in the constraint, otherwise the save won't work and it doesn't throws any exception&lt;br /&gt;face.nose = null &lt;br /&gt;face.save()&lt;br /&gt;println face&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In the above relationship, the foreign key (i.e. nose_id) will added in the Face side. But you can still get hold of face from the nose, because nose belongsTo face.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-6691072136244448966?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/6691072136244448966/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=6691072136244448966' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/6691072136244448966'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/6691072136244448966'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2009/06/bbelongsto.html' title='Digesting belongsTo'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-8574519288618933324</id><published>2009-06-26T12:39:00.005+01:00</published><updated>2009-06-26T12:48:32.982+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>No row with the given identifier exists</title><content type='html'>&lt;div&gt;&lt;div style="text-align: center;"&gt;&lt;span class="Apple-style-span"   style="  white-space: pre; font-family:Arial;font-size:13px;"&gt;&lt;b&gt;No row with the given identifier exists&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;class A {&lt;/div&gt;&lt;div&gt; B b&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;class B {&lt;div&gt; String name&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you have an A has B relationship. If from the database end, A says has B and with B's id, but actually that B's id doesn't exist in B's table. Then it will complains: No row with the given identifier exists&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A workaround of this is to use ignoreNoFound like below&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;class A {&lt;/div&gt;&lt;div&gt;  B b&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;  static mapping = { &lt;/div&gt;&lt;div&gt;    b ignoreNotfound : true&lt;/div&gt;&lt;div&gt;  }&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-8574519288618933324?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/8574519288618933324/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=8574519288618933324' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/8574519288618933324'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/8574519288618933324'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2009/06/no-row-with-given-identifier-exists.html' title='No row with the given identifier exists'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-7288484343027101912</id><published>2009-03-20T11:06:00.004Z</published><updated>2009-03-20T11:13:29.188Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Submit an array as a parameter</title><content type='html'>When you have an array of values to submit like the code below:&lt;br /&gt;&lt;br /&gt;&amp;lt;g:each in="${people}" var="person"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&lt;br /&gt;&amp;lt;input type="checkbox" name="emails[]" value="${person.email}" /&amp;gt;&lt;br /&gt;&amp;lt;td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;&amp;lt;/g:each&amp;gt;&lt;br /&gt;&lt;br /&gt;When submiting this form, the emails[] will be submitted as an array/list object like [Ljava.lang.String;@151313a. To get the value out of the object, do:&lt;br /&gt;&lt;br /&gt;params['emails[]'].toString()&lt;br /&gt;&lt;br /&gt;That will get the value like: [joe@foo.com, blog@foo.com]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-7288484343027101912?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/7288484343027101912/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=7288484343027101912' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/7288484343027101912'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/7288484343027101912'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2009/03/submit-array-as-parameter.html' title='Submit an array as a parameter'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-7064895243076144323</id><published>2009-01-20T17:20:00.005Z</published><updated>2009-04-24T15:41:41.921+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='remote'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Remote Deploy Grails Application</title><content type='html'>&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Ant 1.6 or later support scp, ssh tasks.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;Download the lastest &lt;a href="http://ant.apache.org/"&gt;ant&lt;/a&gt;.&lt;div&gt;Set ANT_HOME variable.&lt;/div&gt;&lt;div&gt;Add %ANT_HOME%\bin in the PATH variable (in Windows environment).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Download the &lt;a href="http://www.jcraft.com/jsch/"&gt;JSch&lt;/a&gt; jar to the %ANT_HOME%\lib&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Add the remote task in the build.xml in the Grails project:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;    &amp;lt;target name="remoteDeploy" depends="war" description="--&amp;gt;Deploy the war to the remote server"&amp;gt;&lt;/div&gt;&lt;div&gt;        &amp;lt;scp file="LockerJet.war" trust="yes"              todir="username:password@remotehost:/PATH_TO_TOMCAT/webapps"/&amp;gt;&lt;/div&gt;&lt;div&gt;    &amp;lt;/target&amp;gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Note: set trust="yes", otherwise it will thrown "reject HostKey" or "java.net.UnknownHostException"&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Run the task by:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;ant remoteDeploy&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;===============&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There is another &lt;a href="http://dahernan.net/2008/06/script-to-deploy-grails-applications.html"&gt;Grails remote deploy&lt;/a&gt; using GANT post for reference.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-7064895243076144323?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/7064895243076144323/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=7064895243076144323' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/7064895243076144323'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/7064895243076144323'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2009/01/remote-deploy-grails-application.html' title='Remote Deploy Grails Application'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-635419056865356901</id><published>2009-01-16T11:01:00.002Z</published><updated>2009-01-16T11:22:40.527Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Clear Flash Message in Grails</title><content type='html'>&lt;span class="Apple-style-span" style="font-family: Tahoma; font-size: 15px; "&gt;&lt;div&gt;According to the Grails documentation:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;"Flash is a temporary storage map that stores objects within the session for the next request and the next request only, automatically clearing our the objects held there after the next request completes.&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Tahoma; font-size: 15px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Tahoma; font-size: 15px; "&gt;The flash object is essentially a map (a hash) which you can use to store key value pairs. These values are transparently stored inside the session and then cleared at the end of the next request.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Tahoma; font-size: 15px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Tahoma; font-size: 15px; "&gt;This pattern allows you to use HTTP redirects (which is useful for &lt;a href="http://www.theserverside.com/tt/articles/article.tss?l=RedirectAfterPost)" target="blank"&gt;redirect after post&lt;/a&gt; and retain values that can retrieved from the flash object."&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Tahoma; font-size: 15px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Tahoma; font-size: 15px;"&gt;But just in case the flash message isn't cleared for some unknow reason, there is the code to rescue in your controller:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Tahoma; font-size: 15px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Tahoma; font-size: 15px;"&gt;flash.clear()&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Tahoma; font-size: 15px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-635419056865356901?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/635419056865356901/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=635419056865356901' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/635419056865356901'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/635419056865356901'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2009/01/clear-flash-message-in-grails.html' title='Clear Flash Message in Grails'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-5598556402026116415</id><published>2009-01-15T16:42:00.007Z</published><updated>2010-11-24T16:56:55.354Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Command Object and Error Messages</title><content type='html'>"&lt;a href="http://grails.org/Command+objects+and+Form+Validation"&gt;Grails command Objects&lt;/a&gt; provide a simple mechanism to validate from fields that do not map directly to domain objects. "&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Command Object&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;pre class="brush: groovy" &gt;class JetCommand {&lt;br /&gt;  String number&lt;br /&gt;  String name&lt;br /&gt; &lt;br /&gt;  static constraints = {&lt;br /&gt;    number(blank: false, nullable: false, matches: "\\d+")&lt;br /&gt;    name(nullable: false)&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 19px;"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;The command object class may be defined under src/groovy/ or under grails-app/controllers/. The command object class may also be defined in the same source file as the controller that uses it.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If a custom error message is preferred, then look at the &lt;a href="http://grails.org/Validation+Reference"&gt;corresponding error code&lt;/a&gt; for the above constraints. Add custom error messages in the grails-app/i18n/messages.properties file:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;pre class="brush: groovy"&gt;jetCommand.number.blank=The number can't be blank&lt;br /&gt;jetCommand.number.matches.invalid=The number can only be digital numbers&lt;br /&gt;jetCommand.name.nullable=The name can't be null&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Controller:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;pre class="brush: groovy"&gt;class JetController {&lt;br /&gt;  def jet = { JetCommand cmd -&amp;gt;&lt;br /&gt;  if (cmd.hasErrors()) {&lt;br /&gt;    cmd.errors.allErrors.each {&lt;br /&gt;    println it&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;  &lt;/span&gt;// You don't have to do the following code, because the Grails will handle it for you.&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;  &lt;/span&gt;// If you do the following code, there will be duplicate error messages&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;  &lt;/span&gt;/**&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;  &lt;/span&gt;if (cmd.errors.hasFieldErrors("name")) {&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;   &lt;/span&gt;cmd.errors.rejectValue('choice', 'searchCommand.name.nullable')&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;  &lt;/span&gt;}&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt; if (cmd.errors.hasFieldErrors("number")) {&lt;/div&gt;&lt;div&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;if (cmd.errors.getFieldValue("number").isEmpty()) {&lt;/div&gt;&lt;div&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;cmd.errors.rejectValue('number', 'searchCommand.number.blank')&lt;/div&gt;&lt;div&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;}&lt;/div&gt;&lt;div&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;else {&lt;/div&gt;&lt;div&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;  &lt;/span&gt;cmd.errors.rejectValue('number', 'searchCommand.number.matches.invalid')&lt;/div&gt;&lt;div&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;}&lt;/div&gt;&lt;div&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;}&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;  &lt;/span&gt;**/&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;  &lt;/span&gt;render (view: 'admin', model:[jetCommand: cmd, key1: object1, key2: object2])&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;  &lt;/span&gt;}&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;}&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;GSP page&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You can display the error messages in the GSP page:&lt;/div&gt;&lt;br /&gt;&lt;pre class="brush: groovy"&gt;&lt;g:haserrors bean="${jetCommand}"&gt;&lt;br /&gt;  &lt;div class="errors"&gt;    &lt;g:rendererrors as="list" bean="${jetCommand}"&gt;&lt;br /&gt;    &lt;/g:rendererrors&gt;&lt;br /&gt;  &lt;/div&gt;&lt;/g:haserrors&gt;&lt;br /&gt;&lt;div class="value ${hasErrors(bean: jetCommand, field: 'number', 'errors')}"&gt;  &lt;g:textfield name="number"&gt;&lt;br /&gt;  &lt;/g:textfield&gt;&lt;br /&gt;&lt;/div&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Customised Validator&lt;/span&gt;:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;You can also add a customised validator:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;pre class="brush: groovy" &gt;static constraints = {&lt;br /&gt;  number(validator: {&lt;br /&gt;    if (it.isEmpty() || it == null || !(it ==~ /\d+/)) {&lt;br /&gt;      return ['numberJet'] &amp;nbsp;// numberJet is the error code&lt;br /&gt;    }&lt;br /&gt;  })&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In this case, in the messages.properties, you should add a error message with the error code:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;jetCommand.number.numberJet=Number field is not valid&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-5598556402026116415?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/5598556402026116415/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=5598556402026116415' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/5598556402026116415'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/5598556402026116415'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2009/01/command-object-and-error-messages.html' title='Command Object and Error Messages'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-3732306623726214087</id><published>2009-01-14T16:22:00.003Z</published><updated>2009-01-14T17:05:39.862Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Redirect Params in Grails</title><content type='html'>&lt;div&gt;&lt;div&gt;&lt;div&gt;Grails params contain controller, action, and other parameters like below:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;["_action_search":"Search", "choice":"Locker Register", "action":"search", "numb&lt;/div&gt;&lt;div&gt;er":"1", "controller":"lockerRegister"]&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So when doing redirect with all the params like below:&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;class JetController {&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;def search = {&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;redirect (action: "jetAction", params: params)&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;}&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;def jetAction { &lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;// some code here&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;}&lt;br /&gt;&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It might be in a endless redirect loop. &lt;span class="Apple-style-span" style="border-collapse: collapse; font-family: verdana; font-size: 13px; -webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; "&gt;A workaround is to manually specify the parameters your want to redirect. For example: &lt;/span&gt;&lt;/div&gt;&lt;span class="Apple-style-span" style="border-collapse: collapse; font-family: verdana; font-size: 13px; -webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; "&gt;&lt;br /&gt;redirect (action: "testAction", controller: "testController", params:[p1: 'value1', p2: 'value2']) &lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-3732306623726214087?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/3732306623726214087/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=3732306623726214087' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/3732306623726214087'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/3732306623726214087'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2009/01/redirect-params-in-grails.html' title='Redirect Params in Grails'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-5394498064062549871</id><published>2009-01-14T10:22:00.005Z</published><updated>2009-01-14T10:47:00.043Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Put Multiple Objects in the Returning Model in The Controller</title><content type='html'>In controller, you can put multiple objects in a model and return it. You can also pass on the parameters from the request to the model on returning it. For example:&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;class JetController {&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;def test = {&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;return ['key1': object1, 'key2': object2, 'key3': params.person.id]&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;}&lt;br /&gt;&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-5394498064062549871?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/5394498064062549871/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=5394498064062549871' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/5394498064062549871'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/5394498064062549871'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2009/01/put-multiple-objects-in-returning-model.html' title='Put Multiple Objects in the Returning Model in The Controller'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-3021191829814918909</id><published>2009-01-14T10:13:00.005Z</published><updated>2009-01-16T14:09:55.515Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Restart the Application After Changing the Dynamic Finders in Grails</title><content type='html'>When changing the dynamic finders (i.e. find, findAll, findBy) while the grails application is running, you need to restart the application to reflect the changes for the queries. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you set  "logSql=true" in your conf/DataSource.groovy, then you can monitor whether  sql queries reflect your changes.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-3021191829814918909?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/3021191829814918909/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=3021191829814918909' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/3021191829814918909'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/3021191829814918909'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2009/01/restart-application-after-changing.html' title='Restart the Application After Changing the Dynamic Finders in Grails'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-4036905505839671075</id><published>2008-12-10T14:43:00.005Z</published><updated>2009-07-27T10:52:21.562+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Grails generate-views with all the fields</title><content type='html'>grails generate-views domainClass&lt;br /&gt;&lt;br /&gt;By default, it will generate the list view with the first 6 fields including the primary key (i.e. id).&lt;br /&gt;&lt;br /&gt;To tell the grails to generate the list view with all the fields, you can modify the file:&lt;br /&gt;&lt;br /&gt;$GRAILS_HOME\src\grails\templates\scaffolding\lis.gsp&lt;br /&gt;&lt;br /&gt;Then change the 6 in the "if (i &lt; 6)" to a big number. There are two places to change, one is for the table column headers, the other is the row data.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-4036905505839671075?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/4036905505839671075/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=4036905505839671075' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/4036905505839671075'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/4036905505839671075'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2008/12/grails-generate-views-with-all-fields.html' title='Grails generate-views with all the fields'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-1656497160921697610</id><published>2008-08-18T23:47:00.001+01:00</published><updated>2008-08-18T23:49:50.521+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Debugging GSP</title><content type='html'>When debugging GSP, you can use ?showSource at the end of the request url to show the comiled Java code to spot on the lines with erros.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-1656497160921697610?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/1656497160921697610/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=1656497160921697610' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/1656497160921697610'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/1656497160921697610'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2008/08/debugging-gsp.html' title='Debugging GSP'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-1358510398331598551</id><published>2008-08-18T16:23:00.001+01:00</published><updated>2008-08-18T16:23:54.271+01:00</updated><title type='text'>Remote Debug Application on Tomcat</title><content type='html'>&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-1358510398331598551?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://wiki.apache.org/tomcat/FAQ/Developing' title='Remote Debug Application on Tomcat'/><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/1358510398331598551/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=1358510398331598551' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/1358510398331598551'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/1358510398331598551'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2008/08/remote-debug-application-on-tomcat.html' title='Remote Debug Application on Tomcat'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-2591611943350966175</id><published>2008-08-04T16:53:00.003+01:00</published><updated>2009-01-16T14:17:34.076Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>REST with Grails</title><content type='html'>&lt;div id="c_8s" style="text-align: left;"&gt;Please refer to &lt;a title="Grails Documentations" href="http://grails.org/doc/1.0.x/guide/13.%20Web%20Services.html#13.1%20REST" id="s34:"&gt;Grails Documentations&lt;/a&gt; for more info on REST with Grails.        &lt;/div&gt;&lt;div id="c_8s" style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id="c_8s" style="text-align: left;"&gt;1. Create a grails project  grails create-app rest  &lt;/div&gt;&lt;div id="c_8s" style="text-align: left;"&gt;2. Create a domain class with name Book  &lt;/div&gt;&lt;div id="c_8s" style="text-align: left;"&gt;create domain-class Book&lt;/div&gt;&lt;div id="c_8s" style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id="c_8s" style="text-align: left;"&gt;class Book {     &lt;/div&gt;&lt;div id="c_8s" style="text-align: left;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;String title     &lt;/div&gt;&lt;div id="c_8s" style="text-align: left;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;String publisher &lt;/div&gt;&lt;div id="c_8s" style="text-align: left;"&gt;} &lt;br /&gt;&lt;/div&gt;&lt;div id="c_8s" style="text-align: left;"&gt;3. Use generate-all to generate views and controller  &lt;/div&gt;&lt;div id="c_8s" style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id="c_8s" style="text-align: left;"&gt;grails generate-all Book   &lt;/div&gt;&lt;div id="c_8s" style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id="c_8s" style="text-align: left;"&gt;4. Modify Bootstrap.groovy to add sample data.&lt;br /&gt;&lt;/div&gt;&lt;pre id="vckx"&gt;class BootStrap {      &lt;/pre&gt;&lt;pre id="vckx"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;def init = { servletContext -&amp;gt;          &lt;/pre&gt;&lt;pre id="vckx"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;new Book(title:"game1",publisher:"pub1").save()         &lt;/pre&gt;&lt;pre id="vckx"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;new Book(title:"game2",publisher:"pub1").save()          &lt;/pre&gt;&lt;pre id="vckx"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;new Book(title:"game3",publisher:"pub2").save()          &lt;/pre&gt;&lt;pre id="vckx"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;new Book(title:"game4",publisher:"pub2").save()      &lt;/pre&gt;&lt;pre id="vckx"&gt;}      &lt;/pre&gt;&lt;pre id="vckx"&gt;def destroy = {      } }    &lt;/pre&gt;&lt;pre id="vckx"&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre id="vckx"&gt;5. Modify UrlMappings.groovy  &lt;span id="dyu5" class="java-keyword"&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre id="vckx"&gt;&lt;span id="dyu5" class="java-keyword"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;static&lt;/span&gt; mappings = {    &lt;span id="dyu51" class="java-quote"&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre id="vckx"&gt;&lt;span id="dyu51" class="java-quote"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;"/book/$id?"&lt;/span&gt;(controller:&lt;span id="dyu52" class="java-quote"&gt;"book"&lt;/span&gt;){        &lt;/pre&gt;&lt;pre id="vckx"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;   &lt;/span&gt;action = [GET:&lt;span id="dyu54" class="java-quote"&gt;"show"&lt;/span&gt;, PUT:&lt;span id="dyu55" class="java-quote"&gt;"update"&lt;/span&gt;, DELETE:&lt;span id="dyu56" class="java-quote"&gt;"delete"&lt;/span&gt;, POST:&lt;span id="dyu57" class="java-quote"&gt;"save"&lt;/span&gt;]    &lt;/pre&gt;&lt;pre id="vckx"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;}  &lt;/pre&gt;&lt;pre id="vckx"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;}  &lt;/pre&gt;6. Modify BookController.groovy show method  &lt;pre id="c7ta1"&gt;&lt;span id="c7ta2" class="java-keyword"&gt;import&lt;/span&gt; grails.converters.* class BookController {  &lt;/pre&gt;&lt;pre id="c7ta1"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;def show = {   &lt;span id="c7ta6" class="java-keyword"&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre id="c7ta1"&gt;&lt;span id="c7ta6" class="java-keyword"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;if&lt;/span&gt;(params.id &amp;amp;&amp;amp; Book.exists(params.id)) {    &lt;/pre&gt;&lt;pre id="c7ta1"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;   &lt;/span&gt;def b = Book.get(params.id)    &lt;/pre&gt;&lt;pre id="c7ta1"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;   &lt;/span&gt;render b as XML   &lt;/pre&gt;&lt;pre id="c7ta1"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;}   &lt;span id="c7ta11" class="java-keyword"&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre id="c7ta1"&gt;&lt;span id="c7ta11" class="java-keyword"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;else&lt;/span&gt; {    &lt;/pre&gt;&lt;pre id="c7ta1"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;   &lt;/span&gt;def all = Product.list()    &lt;/pre&gt;&lt;pre id="c7ta1"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;   &lt;/span&gt;render all as XML   &lt;/pre&gt;&lt;pre id="c7ta1"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;}  &lt;/pre&gt;&lt;pre id="c7ta1"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;}  &lt;/pre&gt;&lt;pre id="c7ta1"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;.. &lt;/pre&gt;&lt;pre id="c7ta1"&gt;}   &lt;/pre&gt;&lt;pre id="c7ta1"&gt;The method can be tested with this showTest.groovy client   &lt;/pre&gt;&lt;pre id="c7ta1"&gt;import org.apache.commons.httpclient.*; &lt;/pre&gt;&lt;pre id="c7ta1"&gt;import org.apache.commons.httpclient.methods.*; &lt;/pre&gt;&lt;pre id="c7ta1"&gt;def url = "http://localhost:8080/rest/book/${args[0]}" &lt;/pre&gt;&lt;pre id="c7ta1"&gt;def method = new GetMethod(url)    &lt;/pre&gt;&lt;pre id="c7ta1"&gt;// Require HTTPClient library &lt;/pre&gt;&lt;pre id="c7ta1"&gt;def client = new HttpClient() &lt;/pre&gt;&lt;pre id="c7ta1"&gt;def statusCode = client.executeMethod(method) &lt;/pre&gt;&lt;pre id="c7ta1"&gt;println "STATUS CODE:$statusCode" &lt;/pre&gt;&lt;pre id="c7ta1"&gt;def stream = method.getResponseBodyAsStream() &lt;/pre&gt;&lt;pre id="c7ta1"&gt;println "--- START RESPONSE BODY --- " &lt;/pre&gt;&lt;pre id="c7ta1"&gt;System.out &amp;lt;&amp;lt; stream println "n--- END RESPONSE BODY ---" &lt;/pre&gt;&lt;pre id="c7ta1"&gt;stream.close() method.releaseConnection()  &lt;/pre&gt;&lt;pre id="c7ta1"&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre id="c7ta1"&gt;Notes: You need to put Apache Commons &lt;a title="Codec" href="http://commons.apache.org/codec/" id="wice"&gt;Codec&lt;/a&gt;, and &lt;a title="HTTPClient" href="http://hc.apache.org/" id="gjxr"&gt;HTTPClient&lt;/a&gt; jars in the $GROOVY_HOMElib    &lt;/pre&gt;&lt;pre id="c7ta1"&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre id="c7ta1"&gt;7. Modify BookController.groovy save method  &lt;/pre&gt;&lt;pre id="c7ta1"&gt;def save = {     &lt;/pre&gt;&lt;pre id="c7ta1"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;def book = new Book(params['book'])     &lt;/pre&gt;&lt;pre id="c7ta1"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;if(book.save())         &lt;/pre&gt;&lt;pre id="c7ta1"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;render book as XML     &lt;/pre&gt;&lt;pre id="c7ta1"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;else{         &lt;/pre&gt;&lt;pre id="c7ta1"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;def myerrors = game.errors.allErrors.collect { &lt;/pre&gt;&lt;pre id="c7ta1"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;   &lt;/span&gt;g.message(error:it) &lt;/pre&gt;&lt;pre id="c7ta1"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;}         &lt;/pre&gt;&lt;pre id="c7ta1"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;render(contentType:"text/xml") {             &lt;/pre&gt;&lt;pre id="c7ta1"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;   &lt;/span&gt;errors {                 &lt;/pre&gt;&lt;pre id="c7ta1"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;    &lt;/span&gt;for(err in myerrors) {                     &lt;/pre&gt;&lt;pre id="c7ta1"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;     &lt;/span&gt;error(err)                 &lt;/pre&gt;&lt;pre id="c7ta1"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;    &lt;/span&gt;}             &lt;/pre&gt;&lt;pre id="c7ta1"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;   &lt;/span&gt;}         &lt;/pre&gt;&lt;pre id="c7ta1"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;}     &lt;/pre&gt;&lt;pre id="c7ta1"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;}         &lt;/pre&gt;&lt;pre id="c7ta1"&gt;}  &lt;/pre&gt;&lt;pre id="c7ta1"&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre id="c7ta1"&gt;You can test the method with the client saveTest.groovy below:  &lt;/pre&gt;&lt;pre id="c7ta1"&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre id="c7ta1"&gt;import org.apache.commons.httpclient.*; &lt;/pre&gt;&lt;pre id="c7ta1"&gt;import org.apache.commons.httpclient.methods.*; &lt;/pre&gt;&lt;pre id="c7ta1"&gt;def url = "http://localhost:8080/rest/game" &lt;/pre&gt;&lt;pre id="c7ta1"&gt;def method = new PostMethod(url) &lt;/pre&gt;&lt;pre id="c7ta1"&gt;def client = new HttpClient() &lt;/pre&gt;&lt;pre id="c7ta1"&gt;def payload = """ &amp;lt;book&amp;gt;   &lt;/pre&gt;&lt;pre id="c7ta1"&gt;&amp;lt;title&amp;gt;newgame&amp;lt;/title&amp;gt;   &lt;/pre&gt;&lt;pre id="c7ta1"&gt;&amp;lt;publisher&amp;gt;&lt;/pre&gt;&lt;pre id="c7ta1"&gt;newpublisher&amp;lt;/publisher&amp;gt; &lt;/pre&gt;&lt;pre id="c7ta1"&gt;&amp;lt;/book&amp;gt; &lt;/pre&gt;&lt;pre id="c7ta1"&gt;""" method.addRequestHeader("Content-Type","text/xml") method.addRequestHeader("Accept","text/xml,application/xml;q=0.9") method.setRequestEntity(new StringRequestEntity(payload)) def statusCode = client.executeMethod(method) println "STATUS CODE:$statusCode" def stream = method.getResponseBodyAsStream() println "--- START RESPONSE BODY --- " System.out &amp;lt;&amp;lt; stream println "n--- END RESPONSE BODY ---" stream.close() method.releaseConnection() &lt;/pre&gt;&lt;pre id="d1ua8"&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-2591611943350966175?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/2591611943350966175/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=2591611943350966175' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/2591611943350966175'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/2591611943350966175'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2008/08/rest-with-grails-please-refer-to-grails.html' title='REST with Grails'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-8888156814723625257</id><published>2008-07-29T16:57:00.001+01:00</published><updated>2008-07-29T16:58:29.750+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Groovlets</title><content type='html'>&lt;pre id="hkcy" class="code-xml"&gt;&lt;span id="hkcy0" class="code-tag"&gt;For more details please refer to: &lt;a title="Groovlets" href="http://docs.codehaus.org/display/GROOVY/Groovlets" id="a:f:"&gt;Groovlets&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1. Put the following lines into web.xml in WEB-INF foler&lt;br /&gt;&lt;br /&gt;=====================================&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;div id="hizy4" class="code panel" style="border-width: 1px;"&gt;&lt;div id="hizy5" class="codeContent panelContent"&gt; &lt;pre id="hizy6" class="code-xml"&gt;&lt;span id="hizy7" class="code-tag"&gt;&amp;lt;servlet&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span id="hizy9" class="code-tag"&gt;&amp;lt;servlet-name&amp;gt;&lt;/span&gt;Groovy&lt;span id="hizy10" class="code-tag"&gt;&amp;lt;/servlet-name&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span id="hizy12" class="code-tag"&gt;&amp;lt;servlet-class&amp;gt;&lt;/span&gt;groovy.servlet.GroovyServlet&lt;span id="hizy13" class="code-tag"&gt;&amp;lt;/servlet-class&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span id="hizy15" class="code-tag"&gt;&amp;lt;/servlet&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span id="hizy18" class="code-tag"&gt;&amp;lt;servlet-mapping&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span id="hizy20" class="code-tag"&gt;&amp;lt;servlet-name&amp;gt;&lt;/span&gt;Groovy&lt;span id="hizy21" class="code-tag"&gt;&amp;lt;/servlet-name&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span id="hizy23" class="code-tag"&gt;&amp;lt;url-pattern&amp;gt;&lt;/span&gt;*.groovy&lt;span id="hizy24" class="code-tag"&gt;&amp;lt;/url-pattern&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span id="hizy26" class="code-tag"&gt;&amp;lt;/servlet-mapping&amp;gt;&lt;br /&gt;&lt;br /&gt;=====================================&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2. Write your Groovlets hello.groovy like below, and put it into the webapps folder&lt;br /&gt;&lt;br /&gt;=====================================&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span id="xzvg6" class="code-keyword"&gt;import&lt;/span&gt; java.util.Date&lt;br /&gt;&lt;span id="xzvg8" class="code-keyword"&gt;import&lt;/span&gt; groovy.xml.MarkupBuilder&lt;br /&gt;&lt;br /&gt;&lt;span id="xzvg11" class="code-keyword"&gt;if&lt;/span&gt; (session == &lt;span id="xzvg12" class="code-keyword"&gt;null&lt;/span&gt;) {&lt;br /&gt; session = request.getSession(&lt;span id="xzvg14" class="code-keyword"&gt;true&lt;/span&gt;);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span id="xzvg18" class="code-keyword"&gt;if&lt;/span&gt; (session.counter == &lt;span id="xzvg19" class="code-keyword"&gt;null&lt;/span&gt;) {&lt;br /&gt;     session.counter = 1&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;html.html {    &lt;span id="xzvg24" class="code-comment"&gt;// html is implicitly bound to &lt;span id="xzvg25" class="code-keyword"&gt;new&lt;/span&gt; MarkupBuilder(out)&lt;br /&gt;&lt;/span&gt;  head {&lt;br /&gt;     title(&lt;span id="xzvg28" class="code-quote"&gt;"Groovy Servlet"&lt;/span&gt;)&lt;br /&gt; }&lt;br /&gt; body {&lt;br /&gt;   p(&lt;span id="xzvg32" class="code-quote"&gt;"Hello, ${request.remoteHost}: ${session.counter}! ${&lt;span id="xzvg33" class="code-keyword"&gt;new&lt;/span&gt; Date()}"&lt;/span&gt;)&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;session.counter = session.counter + 1&lt;br /&gt;&lt;br /&gt;====================================&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt; &lt;/div&gt;&lt;/div&gt;&lt;pre id="hizy30" class="code-xml"&gt;&lt;span id="hizy32" class="code-tag"&gt;3. Copy groovy-all-xyz.jar into WEB-INF/lib folder&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b id="nr3s"&gt;Notes:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;If your Groovlets is at somewhere else rather than $CATALINA_HOME/webapps, then you need to edit the server.xml in the $CATALINA_HOME/conf like below:&lt;br /&gt;&lt;br /&gt;&amp;lt;Context path=&lt;span id="hkcy1" class="code-quote"&gt;"/groovy"&lt;/span&gt; docBase=&lt;span id="hkcy2" class="code-quote"&gt;"c:/groovy-servlet"&lt;/span&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-8888156814723625257?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/8888156814723625257/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=8888156814723625257' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/8888156814723625257'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/8888156814723625257'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2008/07/for-more-details-please-refer-to.html' title='Groovlets'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-1123958699810725456</id><published>2008-07-28T11:27:00.002+01:00</published><updated>2008-07-28T11:30:35.625+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><title type='text'>Set System Properties in Java</title><content type='html'>You can set system properties by using -D in the java command line:&lt;br /&gt;java -Dfile_properties=file.properties HelloWorld &lt;br /&gt;&lt;br /&gt;========================================== &lt;br /&gt;&lt;br /&gt;String file_properties = System.getProperty("file_properties");          &lt;br /&gt;&lt;br /&gt;// load file.properties file which sets the files and directories&lt;br /&gt;       Properties properties = new Properties();&lt;br /&gt;       try {            &lt;br /&gt;//properties.load(new FileInputStream("file.properties"));&lt;br /&gt;           properties.load(new FileInputStream(System.getProperty("file_properties")));         &lt;br /&gt;} catch (FileNotFoundException e1) {            &lt;br /&gt;// TODO Auto-generated catch block            &lt;br /&gt;e1.printStackTrace();        &lt;br /&gt;} catch (IOException e1)&lt;br /&gt; {&lt;br /&gt; // TODO Auto-generated catch block             e1.printStackTrace();        &lt;br /&gt;}        &lt;br /&gt;&lt;br /&gt;// get properties         File inputDir = new File(properties.getProperty("inputDir")); &lt;br /&gt;&lt;br /&gt;========================================== &lt;br /&gt;&lt;br /&gt;In Eclipse, you can set system properties in: &lt;br /&gt;&lt;br /&gt;1. Right click the java program, choose Run As --&amp;gt; Open Run Dialog&lt;br /&gt;2. Select Arguments tab&lt;br /&gt;3. In "VM argument", write your system properties settings. (i.e. -Dfile_properties=file.properties).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-1123958699810725456?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/1123958699810725456/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=1123958699810725456' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/1123958699810725456'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/1123958699810725456'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2008/07/you-can-set-system-properties-by-using.html' title='Set System Properties in Java'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-3319835818468100148</id><published>2008-07-17T15:45:00.002+01:00</published><updated>2008-07-18T14:19:44.398+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XSLT'/><title type='text'>Dealing with namespace in XSLT</title><content type='html'>For more general knowledge about namespace, please refer to &lt;a title="XML Namespaces and How They Affect XPath and XSLT" href="http://msdn.microsoft.com/en-us/library/ms950779.aspx" id="elzc"&gt;XML Namespaces and How They Affect XPath and XSLT&lt;/a&gt; &lt;br id="mknz"&gt;&lt;br id="mknz1"&gt;&lt;br id="mknz2"&gt;If you have an vanilla xml file like below:&lt;br id="x6wu"&gt;&lt;br id="x6wu0"&gt;&amp;lt;people xmlns="http://xmlns.blabla.com/name" xmlns:abc="http://xmlns-abc.blabla.com/abc"&lt;br id="n-dm"&gt;    abc:firstname="jianfeng" &lt;br id="n-dm0"&gt;    abc:lastname="tian" /&amp;gt;&lt;br id="uh.b"&gt;&lt;br id="uh.b0"&gt;In your xslt, you have to define namespaces in your xsl:stylesheet declaration to make it working:&lt;br id="ybnu"&gt;&lt;br id="ybnu0"&gt;    xmlns:jet="http://xmlns.blabla.com/name"&lt;br id="ybnu1"&gt;    xmlns:abc="http://xmlns-abc.blabla.com/abc" &lt;br id="ses4"&gt;&lt;br id="ses40"&gt;&amp;lt;xsl:stylesheet version="2.0" &lt;br id="ztf0"&gt;    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" &lt;br id="ztf00"&gt;    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" &lt;br id="ztf01"&gt;    xmlns:xs="http://www.w3.org/2001/XMLSchema" &lt;br id="ztf02"&gt;    xmlns:jet="http://xmlns.blabla.com/name" &lt;br id="ztf03"&gt;    xmlns:abc="http://xmlns-abc.blabla.com/abc" &lt;br id="ztf04"&gt;    exclude-result-prefixes="abc xs xsi xsl"&amp;gt;&lt;br id="wj2v"&gt;&lt;br id="wj2v0"&gt;    &amp;lt;xsl:output method="xml" encoding="UTF-8" indent="yes"/&amp;gt;&lt;br id="wj2v1"&gt;    &lt;br id="wj2v2"&gt;    &amp;lt;xsl:template match="jet:people"&amp;gt;&lt;br id="nw05"&gt;        &amp;lt;person&amp;gt;&lt;br id="nw050"&gt;&lt;br id="nw051"&gt;            &amp;lt;xsl:attribute name="firstname"&amp;gt;&lt;br id="nw052"&gt;              &amp;lt;xsl:value-of select="@abc:firstname"/&amp;gt;&lt;br id="nw053"&gt;            &amp;lt;/xsl:attribute&amp;gt;&lt;br id="nw054"&gt;&lt;br id="nw055"&gt;            &amp;lt;xsl:attribute name="lastname"&amp;gt;&lt;br id="nw056"&gt;               &amp;lt;xsl:value-of select="@abc:lastname"/&amp;gt;&lt;br id="nw057"&gt;             &amp;lt;/xsl:attribute&amp;gt;&lt;br id="nw058"&gt;&lt;br id="nw059"&gt;        &amp;lt;/person&amp;gt;&lt;br id="b_jk"&gt;&lt;br id="b_jk0"&gt;    &amp;lt;/xsl:template&amp;gt;&lt;br id="b_jk1"&gt;&amp;lt;/xsl:stylesheet&amp;gt;&lt;br id="ypal"&gt;&lt;br id="ypal0"&gt;================================================================&lt;br id="ypal1"&gt;&lt;br id="adpf"&gt;If you have an xml file like below:&lt;br id="adpf0"&gt;&lt;br id="adpf1"&gt;&amp;lt;people xmlns="http://www.somewhere.com/blabla" &amp;gt;&lt;br id="q8d5"&gt;    &amp;lt;person&amp;gt;&lt;br id="u1_t"&gt;     &amp;lt;address&amp;gt;&lt;br id="ju92"&gt;        &amp;lt;postcode&amp;gt;110001&amp;lt;/postcode&amp;gt;&lt;br id="ju920"&gt;     &amp;lt;/address&amp;gt;&lt;br id="l.5i"&gt;     &amp;lt;content group="firstname"&amp;gt;John&amp;lt;/person&amp;gt;&lt;br id="vuw6"&gt;     &amp;lt;content group="lastname"&amp;gt;Smith&amp;lt;/person&amp;gt;&lt;br id="vuw60"&gt;    &amp;lt;/person&amp;gt;&lt;br id="l.5i0"&gt;&amp;lt;/people&amp;gt;&lt;br id="ib-6"&gt;&lt;br id="ib-60"&gt;In your xslt, you have to define namespaces in your xsl:stylesheet declaration to make it working:&lt;br id="q.:0"&gt;    &lt;br id="itda"&gt;    xmlns:jet="http://www.somewhere.com/blabla"&lt;br id="g91t"&gt;&lt;br id="g91t0"&gt;&lt;br id="z1:l"&gt;&amp;lt;xsl:stylesheet version="2.0" &lt;br id="z1:l0"&gt;xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&lt;br id="z1:l1"&gt;xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br id="z1:l2"&gt;xmlns:jet="http://www.somewhere.com/blabla" &lt;br id="z1:l3"&gt;exclude-result-prefixes="jet xsl xsi"&amp;gt;&lt;br id="z1:l4"&gt; &amp;lt;xsl:output method="xml" indent="yes" omit-xml-declaration="no" encoding="ISO-8859-1"/&amp;gt;&lt;br id="z1:l5"&gt;&lt;br id="z1:l6"&gt; &amp;lt;xsl:template match="jet:people"&amp;gt;&lt;br id="z1:l7"&gt;    &amp;lt;data&amp;gt;&lt;br id="z1:l8"&gt;        &amp;lt;postcode&amp;gt;&lt;br id="z1:l9"&gt;         &amp;lt;xsl:value-of select="jet:person/jet:address/jet:postcode"&amp;gt;&lt;br id="xumn"&gt;        &amp;lt;/postcode&amp;gt;&lt;br id="z1:l10"&gt;         &lt;br id="lb4z"&gt;        &amp;lt;firstname&amp;gt;&amp;lt;xsl:value-of select="jet:person/jet:content[@group='firstname']" /&amp;gt;&amp;lt;/login&amp;gt;&lt;br id="grqt"&gt;        &amp;lt;lastname&amp;gt;&amp;lt;xsl:value-of select="jet:person/jet:content[@group='lastname']" /&amp;gt;&amp;lt;/login&amp;gt;&lt;br id="z1:l11"&gt;&lt;br id="z1:l13"&gt;    &amp;lt;/data&amp;gt;&lt;br id="z1:l14"&gt;    &amp;lt;/xsl:template&amp;gt;&lt;br id="z1:l15"&gt;    &lt;br id="z1:l16"&gt;&amp;lt;/xsl:stylesheet&amp;gt;&lt;br id="n-dm1"&gt;&lt;br id="y7-f"&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-3319835818468100148?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/3319835818468100148/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=3319835818468100148' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/3319835818468100148'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/3319835818468100148'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2008/07/if-you-have-vanilla-xml-file-like-below.html' title='Dealing with namespace in XSLT'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-5244558255729749414</id><published>2008-07-04T17:11:00.004+01:00</published><updated>2008-07-17T15:50:50.118+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XSLT'/><title type='text'>Convert CSV to XML Using XSLT</title><content type='html'>Refer to: http://blogs.msdn.com/kaevans/archive/2003/04/17/5780.aspx&lt;br /&gt;&lt;br /&gt;In your CSV file,&lt;br /&gt;&lt;br /&gt;1.  Surround the whole data with &lt;root&gt; tag.&lt;br /&gt;2.  Add &lt;heading&gt; tag to the first row which contains the heading titles&lt;br /&gt;3.  Add &lt;content&gt; tag to contain the whole data.&lt;br /&gt;&lt;br /&gt;&amp;lt;root&amp;gt;&lt;br /&gt;&amp;lt;head&amp;gt;firstname, lastname&amp;lt;/content&amp;gt;&lt;br /&gt;&amp;lt;content&amp;gt;bla, bla&lt;br /&gt;bla, bla&amp;lt;/conent&amp;gt;&lt;br /&gt;&amp;lt;/root&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;xsl:stylesheet version ="2.0" xmlns:xsl ="http://www.w3.org/1999/XSL/Transform" &amp;gt;  &amp;lt;xsl:output method ="xml"/&amp;gt;  &amp;lt;!-- template that matches the root node--&amp;gt;  &amp;lt;xsl:template match ="/" &amp;gt;   &amp;lt;root&amp;gt;    &amp;lt;xsl:call-template name ="texttorows" &amp;gt;     &amp;lt;xsl:with-param name ="StringToTransform" select ="/root/content" /&amp;gt;          &amp;lt;xsl:with-param name="heading" select="/root/heading" /&amp;gt;          &amp;lt;/xsl:call-template&amp;gt;   &amp;lt;/root&amp;gt;  &amp;lt;/xsl:template&amp;gt;    &amp;lt;!-- template that actually does the conversion--&amp;gt;  &amp;lt;xsl:template name ="texttorows" &amp;gt;     &amp;lt;!-- import $StringToTransform--&amp;gt;   &amp;lt;xsl:param name ="StringToTransform" select ="''" /&amp;gt;   &amp;lt;xsl:param name="heading" select="''" /&amp;gt; &amp;lt;!--    &amp;lt;xsl:variable name="CR" select="'&amp;amp;#013;'"/&amp;gt;   --&amp;gt;  &amp;lt;xsl:variable name="CR" select="'&amp;amp;#xA;'"/&amp;gt;     &amp;lt;xsl:choose&amp;gt;    &amp;lt;!-- string contains linefeed--&amp;gt;    &amp;lt;xsl:when test ="contains($StringToTransform,$CR)" &amp;gt;     &amp;lt;!-- Get everything up to the first carriage return--&amp;gt;          &amp;lt;row&amp;gt;      &amp;lt;xsl:call-template name ="csvtoxml" &amp;gt;       &amp;lt;xsl:with-param name ="StringToTransform" select ="substring-before($StringToTransform,$CR)" /&amp;gt;              &amp;lt;xsl:with-param name="heading" select="$heading" /&amp;gt;             &amp;lt;/xsl:call-template&amp;gt;     &amp;lt;/row&amp;gt;     &amp;lt;!-- repeat for the remainder of the original string--&amp;gt;     &amp;lt;xsl:call-template name ="texttorows" &amp;gt;      &amp;lt;xsl:with-param name ="StringToTransform" &amp;gt;       &amp;lt;xsl:value-of select ="substring-after($StringToTransform,$CR)" /&amp;gt;      &amp;lt;/xsl:with-param&amp;gt;      &amp;lt;xsl:with-param name="heading"&amp;gt;       &amp;lt;xsl:value-of select="$heading" /&amp;gt;       &amp;lt;/xsl:with-param&amp;gt;     &amp;lt;/xsl:call-template&amp;gt;    &amp;lt;/xsl:when&amp;gt;    &amp;lt;!-- string does not contain newline, so just output it--&amp;gt;    &amp;lt;xsl:otherwise&amp;gt;     &amp;lt;row&amp;gt;       &amp;lt;xsl:call-template name ="csvtoxml" &amp;gt;       &amp;lt;xsl:with-param name ="StringToTransform" select ="$StringToTransform" /&amp;gt;              &amp;lt;xsl:with-param name="heading" select="$heading" /&amp;gt;             &amp;lt;/xsl:call-template&amp;gt;           &amp;lt;/row&amp;gt;    &amp;lt;/xsl:otherwise&amp;gt;   &amp;lt;/xsl:choose&amp;gt;  &amp;lt;/xsl:template&amp;gt;      &amp;lt;xsl:template name ="csvtoxml" &amp;gt;   &amp;lt;!-- import $StringToTransform--&amp;gt;   &amp;lt;xsl:param name ="StringToTransform" select ="''" /&amp;gt;   &amp;lt;xsl:param name ="heading" select ="''" /&amp;gt;              &amp;lt;xsl:choose&amp;gt;    &amp;lt;!-- string contains linefeed--&amp;gt;    &amp;lt;xsl:when test ="contains($StringToTransform,',')" &amp;gt;     &amp;lt;!-- Get everything up to the first carriage return--&amp;gt;     &amp;lt;elem&amp;gt;      &amp;lt;xsl:value-of select ="substring-before($heading,',')" /&amp;gt;&amp;lt;xsl:text&amp;gt; &amp;lt;/xsl:text&amp;gt;              &amp;lt;xsl:choose&amp;gt;              &amp;lt;xsl:when test="starts-with($StringToTransform, '&amp;amp;quot;')"&amp;gt;              &amp;lt;xsl:value-of select ="substring-before($StringToTransform,'&amp;amp;quot;,')" /&amp;gt;              &amp;lt;/xsl:when&amp;gt;              &amp;lt;xsl:otherwise&amp;gt;              &amp;lt;xsl:value-of select ="substring-before($StringToTransform,',')" /&amp;gt;              &amp;lt;/xsl:otherwise&amp;gt;          &amp;lt;/xsl:choose&amp;gt;     &amp;lt;/elem&amp;gt;     &amp;lt;!-- repeat for the remainder of the original string--&amp;gt;     &amp;lt;xsl:call-template name ="csvtoxml" &amp;gt;           &amp;lt;xsl:with-param name ="heading" &amp;gt;          &amp;lt;xsl:value-of select ="substring-after($heading,',')" /&amp;gt;      &amp;lt;/xsl:with-param&amp;gt;       &amp;lt;xsl:with-param name ="StringToTransform" &amp;gt;          &amp;lt;xsl:choose&amp;gt;              &amp;lt;xsl:when test="starts-with($StringToTransform, '&amp;amp;quot;')"&amp;gt;              &amp;lt;xsl:value-of select ="substring-after($StringToTransform,'&amp;amp;quot;,')" /&amp;gt;              &amp;lt;/xsl:when&amp;gt;              &amp;lt;xsl:otherwise&amp;gt;              &amp;lt;xsl:value-of select ="substring-after($StringToTransform,',')" /&amp;gt;              &amp;lt;/xsl:otherwise&amp;gt;          &amp;lt;/xsl:choose&amp;gt;             &amp;lt;/xsl:with-param&amp;gt;      &amp;lt;/xsl:call-template&amp;gt;    &amp;lt;/xsl:when&amp;gt;    &amp;lt;!-- string does not contain newline, so just output it--&amp;gt;    &amp;lt;xsl:otherwise&amp;gt;     &amp;lt;elem&amp;gt;     &amp;lt;xsl:value-of select ="$heading" /&amp;gt;&amp;lt;xsl:text&amp;gt; &amp;lt;/xsl:text&amp;gt;      &amp;lt;xsl:value-of select ="$StringToTransform" /&amp;gt;     &amp;lt;/elem&amp;gt;    &amp;lt;/xsl:otherwise&amp;gt;   &amp;lt;/xsl:choose&amp;gt;  &amp;lt;/xsl:template&amp;gt; &amp;lt;/xsl:stylesheet&amp;gt;&lt;/content&gt;&lt;/heading&gt;&lt;/root&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-5244558255729749414?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/5244558255729749414/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=5244558255729749414' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/5244558255729749414'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/5244558255729749414'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2008/07/version-2.html' title='Convert CSV to XML Using XSLT'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-2653222137407559590</id><published>2008-07-04T17:00:00.007+01:00</published><updated>2008-07-17T15:50:30.108+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Excel'/><category scheme='http://www.blogger.com/atom/ns#' term='XML'/><title type='text'>Convert CSV to XML in Excel</title><content type='html'>Refer to: http://www.meadinkent.co.uk/xl_xml1.htm&lt;br /&gt;&lt;br /&gt;The easiest way of converting the data in Excel to XML is to use some VB script&lt;br /&gt;&lt;br /&gt;You can create an Excel Macro with the code below. Then in your excel workbook, run the macro.&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px inset ; margin: 0px; padding: 6px; overflow: auto; width: auto; height: 100px;"&gt;&lt;br /&gt;Sub MakeXML()&lt;br /&gt;' create an XML file from an Excel table&lt;br /&gt;Dim MyRow As Integer, MyCol As Integer, Temp As String, YesNo As Variant, DefFolder As String&lt;br /&gt;Dim XMLFileName As String, XMLRecSetName As String, MyLF As String, RTC1 As Integer&lt;br /&gt;Dim RangeOne As String, RangeTwo As String, Tt As String, FldName(99) As String&lt;br /&gt;&lt;br /&gt;MyLF = Chr(10) &amp;amp; Chr(13)    ' a line feed command&lt;br /&gt;DefFolder = "C:\"   'change this to the location of saved XML files&lt;br /&gt;&lt;br /&gt;YesNo = MsgBox("This procedure requires the following data:" &amp;amp; MyLF _&lt;br /&gt;&amp;amp; "1 A filename for the XML file" &amp;amp; MyLF _&lt;br /&gt;&amp;amp; "2 A groupname for an XML record" &amp;amp; MyLF _&lt;br /&gt;&amp;amp; "3 A cellrange containing fieldnames (col titles)" &amp;amp; MyLF _&lt;br /&gt;&amp;amp; "4 A cellrange containing the data table" &amp;amp; MyLF _&lt;br /&gt;&amp;amp; "Are you ready to proceed?", vbQuestion + vbYesNo, "MakeXML CiM")&lt;br /&gt;&lt;br /&gt;If YesNo = vbNo Then&lt;br /&gt;Debug.Print "User aborted with 'No'"&lt;br /&gt;Exit Sub&lt;br /&gt;End If&lt;br /&gt;&lt;br /&gt;XMLFileName = FillSpaces(InputBox("1. Enter the name of the XML file:", "MakeXML CiM", "xl_xml_data"))&lt;br /&gt;If Right(XMLFileName, 4) &lt;&gt; ".xml" Then&lt;br /&gt;XMLFileName = XMLFileName &amp;amp; ".xml"&lt;br /&gt;End If&lt;br /&gt;&lt;br /&gt;XMLRecSetName = FillSpaces(InputBox("2. Enter an identifying name of a record:", "MakeXML CiM", "record"))&lt;br /&gt;&lt;br /&gt;RangeOne = InputBox("3. Enter the range of cells containing the field names (or column titles):", "MakeXML CiM", "A3:D3")&lt;br /&gt;If MyRng(RangeOne, 1) &lt;&gt; MyRng(RangeOne, 2) Then&lt;br /&gt;MsgBox "Error: names must be on a single row" &amp;amp; MyLF &amp;amp; "Procedure STOPPED", vbOKOnly + vbCritical, "MakeXML CiM"&lt;br /&gt;Exit Sub&lt;br /&gt;End If&lt;br /&gt;MyRow = MyRng(RangeOne, 1)&lt;br /&gt;For MyCol = MyRng(RangeOne, 3) To MyRng(RangeOne, 4)&lt;br /&gt;If Len(Cells(MyRow, MyCol).Value) = 0 Then&lt;br /&gt;MsgBox "Error: names range contains blank cell" &amp;amp; MyLF &amp;amp; "Procedure STOPPED", vbOKOnly + vbCritical, "MakeXML CiM"&lt;br /&gt;Exit Sub&lt;br /&gt;End If&lt;br /&gt;FldName(MyCol - MyRng(RangeOne, 3)) = FillSpaces(Cells(MyRow, MyCol).Value)&lt;br /&gt;Next MyCol&lt;br /&gt;&lt;br /&gt;RangeTwo = InputBox("4. Enter the range of cells containing the data table:", "MakeXML CiM", "A4:D8")&lt;br /&gt;If MyRng(RangeOne, 4) - MyRng(RangeOne, 3) &lt;&gt; MyRng(RangeTwo, 4) - MyRng(RangeTwo, 3) Then&lt;br /&gt;MsgBox "Error: number of field names &lt;&gt; data columns" &amp;amp; MyLF &amp;amp; "Procedure STOPPED", vbOKOnly + vbCritical, "MakeXML CiM"&lt;br /&gt;Exit Sub&lt;br /&gt;End If&lt;br /&gt;RTC1 = MyRng(RangeTwo, 3)&lt;br /&gt;&lt;br /&gt;If InStr(1, XMLFileName, ":\") = 0 Then&lt;br /&gt;XMLFileName = DefFolder &amp;amp; XMLFileName&lt;br /&gt;End If&lt;br /&gt;&lt;br /&gt;Open XMLFileName For Output As #1&lt;br /&gt;Print #1, ""&lt;br /&gt;Print #1, "&lt;meadinkent&gt;"&lt;br /&gt;&lt;br /&gt;For MyRow = MyRng(RangeTwo, 1) To MyRng(RangeTwo, 2)&lt;br /&gt;Print #1, "&lt;" &amp;amp; XMLRecSetName &amp;amp; "&gt;"&lt;br /&gt;For MyCol = RTC1 To MyRng(RangeTwo, 4)&lt;br /&gt;' the next line uses the FormChk function to format dates and numbers&lt;br /&gt;   Print #1, "&lt;" &amp;amp; FldName(MyCol - RTC1) &amp;amp; "&gt;" &amp;amp; RemoveAmpersands(FormChk(MyRow, MyCol)) &amp;amp; "&lt;!--" &amp;amp; FldName(MyCol - RTC1) &amp;amp; "--&gt;"&lt;br /&gt;' the next line does not apply any formatting&lt;br /&gt;'  Print #1, "&lt;" &amp;amp; FldName(MyCol - RTC1) &amp;amp; "&gt;" &amp;amp; RemoveAmpersands(Cells(MyRow, MyCol).Value) &amp;amp; "&lt;!--" &amp;amp; FldName(MyCol - RTC1) &amp;amp; "--&gt;"&lt;br /&gt;  Next MyCol&lt;br /&gt;Print #1, "&lt;!--" &amp;amp; XMLRecSetName &amp;amp; "--&gt;"&lt;br /&gt;&lt;br /&gt;Next MyRow&lt;br /&gt;Print #1, "&lt;/meadinkent&gt;"&lt;br /&gt;Close #1&lt;br /&gt;MsgBox XMLFileName &amp;amp; " created." &amp;amp; MyLF &amp;amp; "Process finished", vbOKOnly + vbInformation, "MakeXML CiM"&lt;br /&gt;Debug.Print XMLFileName &amp;amp; " saved"&lt;br /&gt;End Sub&lt;br /&gt;Function MyRng(MyRangeAsText As String, MyItem As Integer) As Integer&lt;br /&gt;' analyse a range, where MyItem represents 1=TR, 2=BR, 3=LHC, 4=RHC&lt;br /&gt;&lt;br /&gt;Dim UserRange As Range&lt;br /&gt;Set UserRange = Range(MyRangeAsText)&lt;br /&gt;Select Case MyItem&lt;br /&gt;Case 1&lt;br /&gt;MyRng = UserRange.Row&lt;br /&gt;Case 2&lt;br /&gt;MyRng = UserRange.Row + UserRange.Rows.Count - 1&lt;br /&gt;Case 3&lt;br /&gt;MyRng = UserRange.Column&lt;br /&gt;Case 4&lt;br /&gt;MyRng = UserRange.Columns(UserRange.Columns.Count).Column&lt;br /&gt;End Select&lt;br /&gt;Exit Function&lt;br /&gt;&lt;br /&gt;End Function&lt;br /&gt;Function FillSpaces(AnyStr As String) As String&lt;br /&gt;' remove any spaces and replace with underscore character&lt;br /&gt;Dim MyPos As Integer&lt;br /&gt;MyPos = InStr(1, AnyStr, " ")&lt;br /&gt;Do While MyPos &gt; 0&lt;br /&gt;Mid(AnyStr, MyPos, 1) = "_"&lt;br /&gt;MyPos = InStr(1, AnyStr, " ")&lt;br /&gt;Loop&lt;br /&gt;FillSpaces = LCase(AnyStr)&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function FormChk(RowNum As Integer, ColNum As Integer) As String&lt;br /&gt;' formats numeric and date cell values to comma 000's and DD MMM YY&lt;br /&gt;FormChk = Cells(RowNum, ColNum).Value&lt;br /&gt;If IsNumeric(Cells(RowNum, ColNum).Value) Then&lt;br /&gt;FormChk = Format(Cells(RowNum, ColNum).Value, "#,##0 ;(#,##0)")&lt;br /&gt;End If&lt;br /&gt;If IsDate(Cells(RowNum, ColNum).Value) Then&lt;br /&gt;FormChk = Format(Cells(RowNum, ColNum).Value, "dd mmm yy")&lt;br /&gt;End If&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function RemoveAmpersands(AnyStr As String) As String&lt;br /&gt;Dim MyPos As Integer&lt;br /&gt;' replace Ampersands (&amp;amp;) with plus symbols (+)&lt;br /&gt;&lt;br /&gt;MyPos = InStr(1, AnyStr, "&amp;amp;")&lt;br /&gt;Do While MyPos &gt; 0&lt;br /&gt;Mid(AnyStr, MyPos, 1) = "+"&lt;br /&gt;MyPos = InStr(1, AnyStr, "&amp;amp;")&lt;br /&gt;Loop&lt;br /&gt;RemoveAmpersands = AnyStr&lt;br /&gt;End Function&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-2653222137407559590?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/2653222137407559590/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=2653222137407559590' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/2653222137407559590'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/2653222137407559590'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2008/07/convert-csv-to-xml-in-excel.html' title='Convert CSV to XML in Excel'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-2261613438476748489</id><published>2008-07-03T15:12:00.003+01:00</published><updated>2008-07-17T15:50:02.972+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>Increase Java heap size</title><content type='html'>Refer to: http://hausheer.osola.com/docs/5&lt;br /&gt;&lt;br /&gt;"&lt;br /&gt;If Java runs out of memory, the following error occurs:&lt;br /&gt;&lt;br /&gt;Exception in thread "main" java.lang.OutOfMemoryError: Java heap space&lt;br /&gt;&lt;br /&gt;This can have two reasons:&lt;br /&gt;&lt;br /&gt;   * Your Java application has a memory leak. There are tools like YourKit Java Profiler that help you to identify such leaks.&lt;br /&gt;   * Your Java application really needs a lot of memory (more than 128 MB by default!). In this case the Java heap size can be increased using the following runtime parameters:&lt;br /&gt;&lt;br /&gt;java -Xms&lt;initial heap="" size=""&gt; -Xmx&lt;maximum heap="" size=""&gt;&lt;br /&gt;&lt;br /&gt;Defaults are:&lt;br /&gt;&lt;br /&gt;java -Xms32m -Xmx128m&lt;br /&gt;&lt;br /&gt;You can set this either in the Java Control Panel or on the command line, depending on the environment you run your application.&lt;br /&gt;&lt;br /&gt;"&lt;/maximum&gt;&lt;/initial&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-2261613438476748489?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/2261613438476748489/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=2261613438476748489' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/2261613438476748489'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/2261613438476748489'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2008/07/increase-java-heap-size.html' title='Increase Java heap size'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-7365795269059768001</id><published>2008-05-14T16:10:00.006+01:00</published><updated>2011-01-21T10:39:50.627Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Log4J'/><category scheme='http://www.blogger.com/atom/ns#' term='XSLT'/><title type='text'>Write Logs to Different Files Using Log4J</title><content type='html'>If you have one generic java program to transform xml files from different directory. &lt;br /&gt;&lt;br /&gt;java -Dfile_properties=/path/to/file.properties -jar YourProgramm.jar&lt;br /&gt;&lt;br /&gt;You can specify different file.properties input directory using the "-D" parameter in the command line. &lt;br /&gt;&lt;br /&gt;In each file.properties file, you specify:&lt;br /&gt;&lt;br /&gt;input_dir=/bla/bla&lt;br /&gt;xslt_dir=/bla/bla&lt;br /&gt;output_dir=/bla/bla&lt;br /&gt;log4j_properties=/bla/bla&lt;br /&gt;&lt;br /&gt;Because you might want different logs for different transformations from different source, thus you can spot on which source file cause the problem.&lt;br /&gt;&lt;br /&gt;By default, if you don't specify where to load the log4j configurations, it will load the log4j.properties, and then log4j.xml from the class folder, which would be uneditable when put in a jar. This might not what you want. You want to specify an external log4j configuration which you can edit outside of the program. &lt;br /&gt;&lt;br /&gt;Here is what you can do:&lt;br /&gt;&lt;br /&gt;Put the xml log4j file (e.g. xmllog4jconfig.xml) in the project directory. &lt;br /&gt;&lt;br /&gt;In your java program&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px inset ; margin: 0px; padding: 6px; overflow: auto; width: auto; height: 250px;"&gt;Public class Transformer {&lt;br /&gt;&lt;br /&gt;private static Logger logger = Logger.getLogger(SaxonTransform.class);&lt;br /&gt;&lt;br /&gt;public static void main(String[] args) {&lt;br /&gt;&lt;br /&gt;DOMConfigurator.configure("xmllog4jconfig.xml");&lt;br /&gt;logger.debug("Here is some DEBUG");&lt;br /&gt;logger.info("Here is some INFO");&lt;br /&gt;logger.warn("Here is some WARN");&lt;br /&gt;logger.error("Here is some ERROR");&lt;br /&gt;logger.fatal("Here is some FATAL");&lt;br /&gt;}&lt;br /&gt;}    &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In the log4j xml configuration file, you can use LevelRange filter to log different levels of information into different log files like below:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px inset ; margin: 0px; padding: 6px; overflow: auto; width: auto; height: 300px;"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;!DOCTYPE log4j:configuration SYSTEM "log4j.dtd" &amp;gt;&lt;br /&gt;&amp;lt;log4j:configuration&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- log without a filter --&amp;gt;&lt;br /&gt;&amp;lt;appender name="file"&lt;br /&gt;class="org.apache.log4j.FileAppender"&amp;gt;&lt;br /&gt;&amp;lt;param name="File" value="logs/test.log" /&amp;gt;&lt;br /&gt;&amp;lt;layout class="org.apache.log4j.PatternLayout"&amp;gt;&lt;br /&gt;&amp;lt;param name="ConversionPattern"&lt;br /&gt;value="%d{ABSOLUTE} %5p %c{1}:%L - %m%n" /&amp;gt;&lt;br /&gt;&amp;lt;/layout&amp;gt;&lt;br /&gt;&amp;lt;/appender&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- log with a filter --&amp;gt;&lt;br /&gt;&amp;lt;appender name="debugfile"&lt;br /&gt;class="org.apache.log4j.FileAppender"&amp;gt;&lt;br /&gt;&amp;lt;param name="File" value="logs/debug.log" /&amp;gt;&lt;br /&gt;&amp;lt;layout class="org.apache.log4j.PatternLayout"&amp;gt;&lt;br /&gt;&amp;lt;param name="ConversionPattern"&lt;br /&gt;value="%d{ABSOLUTE} %5p %c{1}:%L - %m%n" /&amp;gt;&lt;br /&gt;&amp;lt;/layout&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- set the filter --&amp;gt;&lt;br /&gt;&amp;lt;filter class="org.apache.log4j.varia.LevelRangeFilter"&amp;gt;&lt;br /&gt;&amp;lt;param name="LevelMin" value="debug" /&amp;gt;&lt;br /&gt;&amp;lt;param name="LevelMax" value="debug" /&amp;gt;&lt;br /&gt;&amp;lt;/filter&amp;gt;&lt;br /&gt;&amp;lt;/appender&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;root&amp;gt;&lt;br /&gt;&amp;lt;priority value="debug"&amp;gt;&amp;lt;/priority&amp;gt;&lt;br /&gt;&amp;lt;appender-ref ref="debugfile" /&amp;gt;&lt;br /&gt;&amp;lt;appender-ref ref="file" /&amp;gt;&lt;br /&gt;&amp;lt;/root&amp;gt;&lt;br /&gt;&amp;lt;/log4j:configuration&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;For more tutorials on Log4J, please have a look at:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://supportweb.cs.bham.ac.uk/documentation/tutorials/docsystem/build/tutorials/log4j/log4j.html"&gt;Log4J Tutorial from The University Of Birmingham&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.laliluna.de/download/log4j-tutorial-en.pdf"&gt;Log4J Tutorial from Laliluna&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-7365795269059768001?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/7365795269059768001/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=7365795269059768001' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/7365795269059768001'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/7365795269059768001'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2008/05/write-logs-to-different-files-using.html' title='Write Logs to Different Files Using Log4J'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-4805332864542494916</id><published>2008-05-06T17:06:00.003+01:00</published><updated>2008-05-06T17:19:35.383+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XSLT'/><title type='text'>Encoding in XSLT</title><content type='html'>If you have an xml document which contains German or French characters, then in your xml declarations, you should write:&lt;br /&gt;&lt;br /&gt;&amp;lt;?xml version="1.0" encoding="ISO-8859-1"?&amp;gt;&lt;br /&gt;&lt;br /&gt;Don't put "UTF-8" for it. It will not work&lt;br /&gt;&lt;br /&gt;When using Java to write an xml fie, do the following:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px inset ; margin: 0px; padding: 6px; overflow: auto; width: auto; height: 180px;"&gt;&lt;br /&gt;File f = new File("newFile.xml");&lt;br /&gt;FileOutputStream fos = new FileOutputStream(f);&lt;br /&gt;OutputStreamWriter osw = new OutputStreamWriter(fos, Charset.forName("ISO-8859-1"));&lt;br /&gt;&lt;br /&gt;// Begin to write an xml file.&lt;br /&gt;osw.append("..");&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Otherwise, if use the FileWriter instead of OutputStreamWriter, the programme will use the system default encoding which cause problems if the xml file contains German or French characters.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-4805332864542494916?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/4805332864542494916/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=4805332864542494916' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/4805332864542494916'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/4805332864542494916'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2008/05/encoding-in-xslt.html' title='Encoding in XSLT'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-5292430460329011</id><published>2008-05-06T12:44:00.008+01:00</published><updated>2008-05-06T17:06:11.263+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XSLT'/><title type='text'>Remove unwanted namespace in XSLT</title><content type='html'>If we have the xslt like below:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px inset ; margin: 0px; padding: 6px; overflow: auto; width: auto; height: 180px;"&gt;&lt;br /&gt;&amp;lt;xsl:stylesheet version="2.0"&lt;br /&gt;xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&lt;br /&gt;xmlns:abc="http://www.abc.com"&lt;br /&gt;xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&amp;gt;&lt;br /&gt;&amp;lt;content&amp;gt;&lt;br /&gt;...&lt;br /&gt;&amp;lt;/content&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/xsl:stylesheet&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The result xml will be look like:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px inset ; margin: 0px; padding: 6px; overflow: auto; width: auto; height: 150px;"&gt;&lt;br /&gt;&amp;lt;conent xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;   xmlns="http://www.polopoly.com/polopoly/cm/xmlio"&lt;br /&gt;   xmlns:abc="http://www.abc.com"&amp;gt;&lt;br /&gt;...&lt;br /&gt;&amp;lt;/conent&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The namespaces in the tag are not what we want. We can remove these namespaces by using&lt;br /&gt;&lt;br /&gt;&lt;b&gt;exclude-result-prefixes="xsl abc xsi"&lt;/b&gt; in the xsl:stylesheet declaration.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-5292430460329011?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.w3schools.com/xsl/el_stylesheet.asp' title='Remove unwanted namespace in XSLT'/><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/5292430460329011/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=5292430460329011' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/5292430460329011'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/5292430460329011'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2008/05/remove-unwanted-namespace-in-xslt.html' title='Remove unwanted namespace in XSLT'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-3201309777569422001</id><published>2008-04-28T16:55:00.008+01:00</published><updated>2008-04-28T17:17:49.461+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XSLT'/><title type='text'>Escape &lt;?xml version="1.0" encoding="UTF-8"?&gt; in XML / XSLT</title><content type='html'>If an xml file is embeded in another xml file like below: &lt;br /&gt;&lt;br /&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;..&lt;br /&gt;&amp;lt;value&amp;gt;&lt;br /&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;name&amp;gt;Your name&amp;lt;/name&amp;gt;&lt;br /&gt;..&lt;br /&gt;&amp;lt;/value&amp;gt;&lt;br /&gt;..&lt;br /&gt;&lt;br /&gt;And you want to extract the embedded xml file and remove its xml declaration tag, then do the following:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px inset ; margin: 0px; padding: 6px; overflow: auto; width: auto; height: 350px;"&gt;&lt;br /&gt;&amp;lt;!-- Disable xml declaration by xslt --&amp;gt;&lt;br /&gt;&amp;lt;xsl:output method="xml" omit-xml-declaration="yes" /&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- Define the string you want to remove --&amp;gt;&lt;br /&gt;&amp;lt;xsl:variable name="declare"&amp;gt;&lt;br /&gt;&amp;lt;![CDATA[&amp;lt?xml version="1.0" encoding="UTF-8"?&amp;gt;]]&amp;gt;&lt;br /&gt;&amp;lt;/xsl:variable&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- Get the embedded xml file --&amp;gt;&lt;br /&gt;&amp;lt;xsl:variable name="prepared"&amp;gt;&lt;br /&gt;&amp;lt;xsl:value-of select="value" /&amp;gt;&lt;br /&gt;&amp;lt;/xsl:variable&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- Remove the xml declaration and escape special characters --&amp;gt;&lt;br /&gt;&amp;lt;xsl:value-of select="substring-after($prepared, $declare)" &lt;br /&gt;disable-output-escaping="yes" /&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-3201309777569422001?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/3201309777569422001/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=3201309777569422001' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/3201309777569422001'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/3201309777569422001'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2008/04/escape-in-xml-xslt.html' title='Escape &amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt; in XML / XSLT'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-1720232503813012073</id><published>2008-04-28T15:48:00.003+01:00</published><updated>2008-04-28T15:52:09.883+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XSLT'/><title type='text'>Define variable using xsl:choose in XSLT</title><content type='html'>&lt;pre style="border: 1px inset ; margin: 0px; padding: 6px; overflow: auto; width: auto; height: 150px;"&gt;&lt;br /&gt;&amp;lt;xsl:variable name="doctype"&amp;gt;&lt;br /&gt;&amp;lt;xsl:choose&amp;gt;&lt;br /&gt;  &amp;lt;xsl:when test="condition1"&gt;value1&amp;lt;/xsl:when&amp;gt;&lt;br /&gt;  &amp;lt;xsl:when test="condition2"&gt;value1&amp;lt;/xsl:when&amp;gt;&lt;br /&gt;&amp;lt;xsl:choose&amp;gt;&lt;br /&gt;&amp;lt;/xsl:variable&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-1720232503813012073?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/1720232503813012073/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=1720232503813012073' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/1720232503813012073'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/1720232503813012073'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2008/04/define-variable-using-xslchoose-in-xslt.html' title='Define variable using xsl:choose in XSLT'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-8823549447503374857</id><published>2008-04-28T15:37:00.005+01:00</published><updated>2008-04-28T15:47:24.026+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XSLT'/><title type='text'>Get filename using XSLT</title><content type='html'>&lt;pre style="border: 1px inset ; margin: 0px; padding: 6px; overflow: auto; width: auto; height: 250px;"&gt;&lt;br /&gt;&amp;lt;!-- Get the filename --&amp;gt;&lt;br /&gt;&amp;lt;xsl:variable name="filename" select="tokenize(base-uri(.), '/')[last()]"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- Split the filename using '\.' --&amp;gt;&lt;br /&gt;&amp;lt;xsl:variable name="filenamepart" select="tokenize($filename, '\.')"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- Remove the file extension --&amp;gt;&lt;br /&gt;&amp;lt;xsl:value-of select="$filenamepart[1]"/&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-8823549447503374857?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/8823549447503374857/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=8823549447503374857' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/8823549447503374857'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/8823549447503374857'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2008/04/get-filename-using-xslt.html' title='Get filename using XSLT'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-8849149498207653609</id><published>2008-04-11T10:57:00.001+01:00</published><updated>2008-07-17T15:51:22.325+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='networking'/><title type='text'></title><content type='html'>&lt;span id="ar36"&gt;&lt;b&gt;How To Make A Web Site On The Local Machine Available To Other Computer Users&lt;/b&gt;&lt;/span&gt;  If you deployed a web site on apache, tomcat, or IIS on port 80, then do the following:  1. Control Panel / Network Connections / Local Area Connection (right click) / Properties  2. Advanced tab / Windows Firewall (click Settings button) / Exception tab / click Add Port button  3. Enter Name (i.e. blackboard), Port number: 80 (TCP).   4. Then click "Change scope" button, select the relevant option.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-8849149498207653609?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/8849149498207653609/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=8849149498207653609' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/8849149498207653609'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/8849149498207653609'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2008/04/how-to-make-web-site-on-local-machine.html' title=''/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-8240563467816048085</id><published>2008-04-08T15:27:00.003+01:00</published><updated>2008-07-17T15:58:25.640+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='UNIX'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>How to Set JAVA_HOME in Linux</title><content type='html'>&lt;div id="e7-3" style="text-align: center;"&gt;&lt;span id="egsr"&gt;&lt;b id="g9vz"&gt;&lt;span id="n9ep"  style="font-size:130%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt; &lt;/div&gt;&lt;span id="egsr"&gt;&lt;b id="g9vz"&gt; Set JAVA_HOME for One User&lt;/b&gt;&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;1. Make sure you are in bash mode by typing  bash&lt;br /&gt;&lt;br /&gt;2. Edit your .bashrc file   vi ~/.bashrc&lt;br /&gt;&lt;br /&gt;3. Add the following lines &lt;br /&gt;&lt;br /&gt;JAVA_HOME=/usr/local/java/jdk1.5.0_15&lt;br /&gt;export JAVA_HOME export PATH=$JAVA_HOME/bin:$PATH&lt;br /&gt;&lt;br /&gt;Make sure put $JAVA_HOME/bin in front of $PATH, so that the system will look for javac and java first in the $JAVA_HOME/bin, and then $PATH. &lt;br /&gt;&lt;br /&gt;4. Refresh the user profile using the following command.  &lt;br /&gt;&lt;br /&gt;source ~/.bashrc &lt;br /&gt;&lt;br /&gt;Note: You have to make sure you are in the bash mode by typing: bash, otherwise the user profile won't be refreshed by the above source command.&lt;br /&gt;&lt;br /&gt;5. Check your variables:&lt;br /&gt;&lt;br /&gt;echo $JAVA_HOME&lt;br /&gt;echo $PATH&lt;br /&gt;which java&lt;br /&gt;which javac   &lt;span id="f7:0"&gt;&lt;b id="br1y"&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Set JAVA_HOME for All Users&lt;/b&gt;&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;1. Login as root. &lt;br /&gt;&lt;br /&gt;2. Change it to bash shell by typing bash  bash &lt;br /&gt;&lt;br /&gt;3. Edit /etc/bashrc file  vi /etc/bashrc &lt;br /&gt;&lt;br /&gt;4. 5. 6 are the same as Set JAVA_Home for One User.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-8240563467816048085?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/8240563467816048085/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=8240563467816048085' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/8240563467816048085'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/8240563467816048085'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2008/04/set-javahome-for-one-user-1.html' title='How to Set JAVA_HOME in Linux'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-4303236400228927055</id><published>2008-01-26T01:33:00.000Z</published><updated>2008-04-11T10:58:09.346+01:00</updated><title type='text'></title><content type='html'>  &lt;div style="text-align: center;"&gt;&lt;h1&gt;      Ant, Log4J, JUnit, Eclipse&lt;/h1&gt;&lt;/div&gt;&lt;br&gt;&lt;h2&gt;1. Technical Specification&lt;/h2&gt;&lt;br&gt;The target application environment Java compiler's version is Java 1.5.&lt;br&gt;Create a project in Eclipse. &lt;br&gt;Need to connect a database (e.g. Oracle).&lt;br&gt;Should log error message using Log4J.&lt;br&gt;Delivery the project as a jar.&lt;br&gt;&lt;br&gt;      &lt;br&gt;&lt;h2&gt;2. Procedures&lt;/h2&gt;&lt;br&gt;2.1 &lt;a title="Create User Library for Log4J and JDBC driver (oracle-jdbc)" href="#2.1_Create_User_Libraries" id="x.n3"&gt;Create User Library for Log4J and JDBC driver (oracle-jdbc)&lt;/a&gt; &lt;br&gt;&lt;br&gt;2.2 &lt;a title="Add these two user libraries to the project build path" href="#2.2_Add_User_Libraries_to_the_pr" id="r_jh"&gt;Add these two user libraries to the project build path&lt;/a&gt; &lt;br&gt;&lt;br&gt;2.3 &lt;a title="Establish The Application Environment in Eclipse" href="#2.3_Establish_Project_Structure" id="wfa9"&gt;Establish The Application Environment in Eclipse&lt;/a&gt; &lt;br&gt;&lt;br&gt;    2.3.1 &lt;a title="Create file.properties file as a property file for the application to read" href="#2.3.1_Create_file.properties_fil" id="tv.m"&gt;Create file.properties file as a property file for the application to read&lt;/a&gt; &lt;br&gt;&lt;br&gt;    2.3.2 &lt;a title="Create a log4j.properties file for log4j to read" href="#2.3.2_In_the_src_directory,_crea" id="gox7"&gt;Create a log4j.properties file for log4j to read&lt;/a&gt; &lt;br&gt;&lt;br&gt;2.4 &lt;a title="Follow the instructions to set up JUnit available to Ant" href="#2.4_Follow_the_instructions_to_s" id="nybh"&gt;Follow the instructions to set up JUnit available to Ant&lt;/a&gt; &lt;br&gt;&lt;br&gt;2.5 &lt;a title="Create build.xml file" href="#2.5_Create_build.xml_file" id="d55w"&gt;Create build.xml file&lt;/a&gt; &lt;br&gt; &lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;a id="szzh" name="2.1_Create_User_Libraries"&gt;&lt;/a&gt;&lt;b&gt;2.1 &lt;/b&gt;&lt;b&gt;Create User Libraries&lt;/b&gt;&lt;br&gt;&lt;br&gt;&lt;div id="y-cy" style="padding: 1em 0pt; text-align: left;"&gt;&lt;img style="width: 618px; height: 383px;" src="http://docs.google.com/File?id=dd8234bp_32hjd7bng7"&gt;&lt;/div&gt;&lt;br&gt;1. In Eclipse, Window &amp;gt; Preferences &amp;gt; Java &amp;gt; Build Path &amp;gt; User Libraries.&lt;br&gt;2. Click New button, and enter the 'user library name'.&lt;br&gt;3. Click Add JARs... button, and select the jar files to be added to this user library. &lt;br&gt;4. Click OK button. &lt;br&gt;&lt;br&gt;Do the above steps for Log4J, and oracle-jdbc&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;a id="z3k3" name="2.2_Add_User_Libraries_to_the_pr"&gt;&lt;/a&gt;&lt;b&gt;2.2 Add User Libraries to the project&lt;/b&gt;&lt;br&gt;&lt;div id="a.qp" style="padding: 1em 0pt; text-align: left;"&gt;&lt;div id="s:8r" style="padding: 1em 0pt; text-align: left;"&gt;&lt;img style="width: 738px; height: 612px;" src="http://docs.google.com/File?id=dd8234bp_34css862rm"&gt;&lt;/div&gt;&lt;br&gt;&lt;/div&gt;&lt;br&gt;1. Right click the project, and select properties (or Alt+Enter).&lt;br&gt;2. Select Java Build Path &amp;gt; Libraries, and click Add Library... button&lt;br&gt;3. Select User Library, and click next&amp;gt; button&lt;br&gt;4. Select lo4j, and oracle-jdbc (the two we just created in the previous step).&lt;br&gt;5. Click OK to add these user libraries to the project environment.&lt;br&gt;&lt;br&gt;Doing this can make sure these libraries are in the project classpath.&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;a id="kl0l" name="2.3_Establish_Project_Structure"&gt;&lt;/a&gt;&lt;b&gt;2.3 Establish Project Structure&lt;/b&gt;&lt;br&gt;&lt;br&gt;&lt;div id="wqih" style="padding: 1em 0pt; text-align: left;"&gt;&lt;img style="width: 247px; height: 383px;" src="http://docs.google.com/File?id=dd8234bp_35f673t3fv"&gt;&lt;/div&gt;1. Create build directory, and its sub directories (classes and jar) &lt;br&gt;    md build/classes&lt;br&gt;    md build/jar&lt;br&gt;2. Create lib directory, and copy log4j and oracle-jdbc jars in.&lt;br&gt;&lt;br&gt;&lt;a id="l9m4" name="2.3.1_Create_file.properties_fil"&gt;&lt;/a&gt;&lt;b&gt;2.3.1 Create file.properties file as a property file for the application to read&lt;/b&gt;&lt;br&gt;    name1 = value1&lt;br&gt;    name2 = value2&lt;br&gt;&lt;br&gt;&lt;a id="o7p:" name="2.3.2_In_the_src_directory,_crea"&gt;&lt;/a&gt;&lt;b&gt;2.3.2 In the src directory, create a log4j.properties file for log4j to read. Below is a sample&lt;/b&gt;&lt;br&gt;&lt;br&gt;    For more info about log4j, please look at: &lt;a title="How to use log4j logging API" target="_blank" href="http://javawords.com/2008/01/08/how-to-use-log4j-logging-api/" id="dx:w"&gt;How to use log4j logging API&lt;/a&gt; and &lt;a title="Log4J Manual" target="_blank" href="http://logging.apache.org/log4j/1.2/manual.html" id="oh-:"&gt;Log4J Manual&lt;/a&gt; &lt;br&gt;&lt;br&gt;************************************************&lt;br&gt;# Log levels&lt;br&gt;# Uncomment the following line to enable full loggin for every class&lt;br&gt;#log4j.rootLogger=trace, stdout, R&lt;br&gt;log4j.logger.pma=error, stdout, R&lt;br&gt; &lt;br&gt;# Console appender configuration&lt;br&gt;log4j.appender.stdout=org.apache.log4j.ConsoleAppender&lt;br&gt;# Pattern to output the caller's file name and line number.&lt;br&gt;log4j.appender.stdout.layout=org.apache.log4j.PatternLayout&lt;br&gt;log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n&lt;br&gt; &lt;br&gt;# Rolling File Appender&lt;br&gt;log4j.appender.R=org.apache.log4j.RollingFileAppender&lt;br&gt;# Path and file name to store the log file.&lt;br&gt;log4j.appender.R.File=./logs/error.log&lt;br&gt;log4j.appender.R.MaxFileSize=500KB&lt;br&gt;# Keep one backup file&lt;br&gt;log4j.appender.R.MaxBackupIndex=1&lt;br&gt;# Rolling File Appender layout&lt;br&gt;log4j.appender.R.layout=org.apache.log4j.PatternLayout&lt;br&gt;log4j.appender.R.layout.ConversionPattern=%d - %c - %p - %m%n&lt;br&gt;&lt;br&gt;****************************************************&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;a id="l-8u" name="2.4_Follow_the_instructions_to_s"&gt;&lt;/a&gt;&lt;b&gt;2.4 Follow the &lt;/b&gt;&lt;a title="instructions" target="_blank" href="http://ant.apache.org/manual/OptionalTasks/junit.html" id="ww.2"&gt;&lt;b&gt;instructions&lt;/b&gt;&lt;/a&gt;&lt;b&gt; to set up JUnit available to Ant&lt;/b&gt;&lt;br&gt;&lt;br&gt;&lt;a id="xpe_" name="2.5_Create_build.xml_file"&gt;&lt;/a&gt;&lt;b&gt;2.5 Create build.xml file&lt;/b&gt;&lt;br&gt;&lt;br&gt;For more information about Ant and its build.xml file, please have a look at &lt;a title="Tutorial: Hello World with Ant" target="_blank" href="http://ant.apache.org/manual/tutorial-HelloWorldWithAnt.html" id="vixe"&gt;Tutorial: Hello World with Ant&lt;/a&gt; &lt;br&gt;&lt;br&gt;Below is a sample build.xml file:&lt;br&gt;&lt;br&gt;********************************************************&lt;br&gt;&lt;br&gt;&amp;lt;?xml version="1.0"?&amp;gt;&lt;br&gt;&lt;br&gt;&amp;lt;project name="pma" basedir="." default="main"&amp;gt;&lt;br&gt;    &amp;lt;property name="src.dir" value="src"&amp;gt;&lt;br&gt;    &amp;lt;/property&amp;gt;&lt;br&gt;    &amp;lt;property name="build.dir" value="build"&amp;gt;&lt;br&gt;    &amp;lt;/property&amp;gt;&lt;br&gt;    &amp;lt;property name="classes.dir" value="${build.dir}/classes"&amp;gt;&lt;br&gt;    &amp;lt;/property&amp;gt;&lt;br&gt;    &amp;lt;property name="jar.dir" value="${build.dir}/jar"&amp;gt;&lt;br&gt;    &amp;lt;/property&amp;gt;&lt;br&gt;    &amp;lt;property name="main-class" value="pma.PMADAO_Split"&amp;gt;&lt;br&gt;    &amp;lt;/property&amp;gt;&lt;br&gt;    &amp;lt;property name="lib.dir" value="lib"&amp;gt;&lt;br&gt;    &amp;lt;/property&amp;gt;&lt;br&gt;    &amp;lt;property name="report.dir" value="${build.dir}/junitreport"&amp;gt;&lt;br&gt;    &amp;lt;/property&amp;gt;&lt;br&gt;&lt;br&gt;    &amp;lt;path id="classpath"&amp;gt;&lt;br&gt;        &amp;lt;fileset dir="${lib.dir}" includes="**/*.jar"&amp;gt;&lt;br&gt;        &amp;lt;/fileset&amp;gt;&lt;br&gt;    &amp;lt;/path&amp;gt;&lt;br&gt;&lt;br&gt;    &amp;lt;target name="clean"&amp;gt;&lt;br&gt;        &amp;lt;delete dir="${build.dir}"&amp;gt;&lt;br&gt;        &amp;lt;/delete&amp;gt;&lt;br&gt;    &amp;lt;/target&amp;gt;&lt;br&gt;&lt;br&gt;    &amp;lt;target name="compile"&amp;gt;&lt;br&gt;        &amp;lt;mkdir dir="${classes.dir}"/&amp;gt;&lt;br&gt;        &amp;lt;javac srcdir="${src.dir}" destdir="${classes.dir}" &lt;br&gt;            classpathref="classpath"&lt;br&gt;            source="1.5"&lt;br&gt;            target="1.5"&lt;br&gt;            compiler="javac1.5"/&amp;gt;&lt;br&gt;        &amp;lt;copy todir="${classes.dir}"&amp;gt;&lt;br&gt;            &amp;lt;fileset dir="${src.dir}" excludes="**/*.java"&amp;gt;&lt;br&gt;            &amp;lt;/fileset&amp;gt;&lt;br&gt;        &amp;lt;/copy&amp;gt;&lt;br&gt;    &amp;lt;/target&amp;gt;&lt;br&gt;&lt;br&gt;    &amp;lt;target name="jar" depends="compile"&amp;gt;&lt;br&gt;        &amp;lt;mkdir dir="${jar.dir}"/&amp;gt;&lt;br&gt;        &amp;lt;jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}" update="true"&amp;gt;&lt;br&gt;&lt;br&gt;            &amp;lt;zipfileset src="${lib.dir}/ojdbc14.jar"/&amp;gt;&lt;br&gt;            &amp;lt;zipfileset src="${lib.dir}/log4j-1.2.15.jar"/&amp;gt;&lt;br&gt;&lt;br&gt;            &amp;lt;manifest&amp;gt;&lt;br&gt;                &amp;lt;attribute name="Main-Class" value="${main-class}"/&amp;gt;&lt;br&gt;            &amp;lt;/manifest&amp;gt;&lt;br&gt;        &amp;lt;/jar&amp;gt;&lt;br&gt;    &amp;lt;/target&amp;gt;&lt;br&gt;&lt;br&gt;    &amp;lt;target name="run" depends="jar"&amp;gt;&lt;br&gt;        &amp;lt;java fork="true" classname="${main-class}"&amp;gt;&lt;br&gt;            &amp;lt;classpath&amp;gt;&lt;br&gt;                &amp;lt;path refid="classpath"&amp;gt;&lt;br&gt;                &amp;lt;/path&amp;gt;&lt;br&gt;                &amp;lt;path id="application" location="${jar.dir}/${ant.project.name}.jar"&amp;gt;&lt;br&gt;                &amp;lt;/path&amp;gt;&lt;br&gt;            &amp;lt;/classpath&amp;gt;&lt;br&gt;        &amp;lt;/java&amp;gt;&lt;br&gt;    &amp;lt;/target&amp;gt;&lt;br&gt;&lt;br&gt;    &amp;lt;target name="clean-build" depends="clean,jar"&amp;gt;&lt;br&gt;    &amp;lt;/target&amp;gt;&lt;br&gt;    &amp;lt;target name="main" depends="clean,run"&amp;gt;&lt;br&gt;    &amp;lt;/target&amp;gt;&lt;br&gt;&lt;br&gt;    &amp;lt;target name="junit" depends="jar"&amp;gt;&lt;br&gt;        &amp;lt;mkdir dir="${report.dir}" /&amp;gt;&lt;br&gt;        &amp;lt;junit printsummary="yes"&amp;gt;&lt;br&gt;            &amp;lt;classpath&amp;gt;&lt;br&gt;                &amp;lt;path refid="classpath" /&amp;gt;&lt;br&gt;                &amp;lt;path refid="application" /&amp;gt;&lt;br&gt;            &amp;lt;/classpath&amp;gt;&lt;br&gt;            &amp;lt;formatter type="xml" /&amp;gt;&lt;br&gt;            &amp;lt;batchtest fork="yes" todir="${report.dir}"&amp;gt;&lt;br&gt;                &amp;lt;fileset dir="${src.dir}" includes="*Test.java" /&amp;gt;&lt;br&gt;            &amp;lt;/batchtest&amp;gt;&lt;br&gt;        &amp;lt;/junit&amp;gt;&lt;br&gt;    &amp;lt;/target&amp;gt;&lt;br&gt;&lt;br&gt;    &amp;lt;target name="junitreport"&amp;gt;&lt;br&gt;        &amp;lt;junitreport todir="${report.dir}"&amp;gt;&lt;br&gt;            &amp;lt;fileset dir="${report.dir}" includes="TEST-*.xml"/&amp;gt;&lt;br&gt;            &amp;lt;report todir="${report.dir}"/&amp;gt;&lt;br&gt;        &amp;lt;/junitreport&amp;gt;&lt;br&gt;    &amp;lt;/target&amp;gt;&lt;br&gt;&lt;br&gt;&amp;lt;/project&amp;gt;&lt;br&gt;&lt;br&gt;**********************************************&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;In the task "jar", the following code can make sure the created jar (pma.jar) file contains the following libraries (log4j, and oracle-jdbc jars) in an extracted format. If the libraries (log4j, and oracle-jdbc jars) in the created jar (pma.jar) are in its jar format, then the application won't find the libraries in its classpath when running.&lt;br&gt;&lt;br&gt;    &amp;lt;zipfileset src="${lib.dir}/ojdbc14.jar"/&amp;gt;&lt;br&gt;    &amp;lt;zipfileset src="${lib.dir}/log4j-1.2.15.jar"/&amp;gt;&lt;br&gt;&lt;br&gt;&lt;div id="p3gw" style="padding: 1em 0pt; text-align: left;"&gt;&lt;img style="width: 255px; height: 233px;" src="http://docs.google.com/File?id=dd8234bp_36h5pchngg"&gt;&lt;/div&gt;&lt;br&gt;In the task "compile", we have to add:&lt;br&gt;&lt;br&gt;source="1.5" target="1.5" compiler="javac1.5" to make the application java 1.5 compatible on the target environment, otherwise it will complains about "class version something" when running. &lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt; &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-4303236400228927055?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/4303236400228927055/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=4303236400228927055' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/4303236400228927055'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/4303236400228927055'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2008/01/ant-log4j-junit-eclipse-1.html' title=''/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-4371812783389622061</id><published>2008-01-15T16:53:00.000Z</published><updated>2008-01-15T16:54:10.125Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='UNIX'/><title type='text'>crontab</title><content type='html'>&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-4371812783389622061?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.adminschoice.com/docs/crontab.htm' title='crontab'/><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/4371812783389622061/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=4371812783389622061' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/4371812783389622061'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/4371812783389622061'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2008/01/crontab.html' title='crontab'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-4536648233818375682</id><published>2008-01-15T16:01:00.000Z</published><updated>2008-01-15T16:16:29.084Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='weblog'/><title type='text'>Weblog Analysis with Webalizer</title><content type='html'>Webalizer is a web log analysis tool which runs very fast. You can download Webalizer &lt;a href="http://www.mrunix.net/webalizer/"&gt;Here.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;By default&lt;br /&gt;&lt;br /&gt;&gt;./webalizer logfile&lt;br /&gt;&lt;br /&gt;will process only one log file. If all the logs are in one file, then it is ok. But for logs which rotate on a daily basis, you have to configure webalizer to do so.&lt;br /&gt;&lt;br /&gt;Here is my webalizer.conf, which should be at the webalizer command directory.&lt;br /&gt;&lt;br /&gt;**********************************************&lt;br /&gt;...&lt;br /&gt;LogType         clf&lt;br /&gt;OutputDir      /outputdirectory&lt;br /&gt;HistoryName     webalizer.hist&lt;br /&gt;Incremental     yes&lt;br /&gt;IncrementalName webalizer.current&lt;br /&gt;...&lt;br /&gt;**********************************************&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Create a script foo.sh like below will do the  business:&lt;br /&gt;&lt;br /&gt;**********************************************&lt;br /&gt;#!/bin/sh&lt;br /&gt;&lt;br /&gt;for file in /logfiles/*&lt;br /&gt;do&lt;br /&gt;/pathtowebalizer/webalizer $file&lt;br /&gt;done&lt;br /&gt;exit 0&lt;br /&gt;**********************************************&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-4536648233818375682?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/4536648233818375682/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=4536648233818375682' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/4536648233818375682'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/4536648233818375682'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2008/01/weblog-analysis-with-webalizer.html' title='Weblog Analysis with Webalizer'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-3967138362601979468</id><published>2008-01-11T10:10:00.000Z</published><updated>2008-01-15T16:18:20.893Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='logging'/><title type='text'>Java Logging using java.util.logging</title><content type='html'>Java's logging facility (see Sun's &lt;a href="http://java.sun.com/j2se/1.4.2/docs/guide/util/logging/overview.html"&gt;overview&lt;/a&gt; and &lt;a href="http://java.sun.com/javase/6/docs/api/java/util/logging/package-summary.html"&gt;API&lt;/a&gt; ) has two parts : a configuration file, and an API for using logging services. It is a good tool, and is perfectly fine for simple and moderate logging needs.  (For &lt;em&gt;complex&lt;/em&gt; logging needs, you might consider the &lt;a href="http://logging.apache.org/log4j/docs/"&gt;log4j&lt;/a&gt; tool as an  alternative.)  &lt;p&gt;Log entries can be sent to these destinations, as either simple text or as XML : &lt;/p&gt;&lt;ul&gt;&lt;li&gt; the console&lt;/li&gt;&lt;li&gt; a file&lt;/li&gt;&lt;li&gt; a stream&lt;/li&gt;&lt;li&gt; memory&lt;/li&gt;&lt;li&gt; a TCP socket on a remote host&lt;/li&gt;&lt;/ul&gt; The &lt;tt&gt;&lt;a href="http://java.sun.com/javase/6/docs/api/java/util/logging/Level.html"&gt;Level&lt;/a&gt;&lt;/tt&gt; class defines seven levels of logging enlightenment : &lt;ul&gt;&lt;li&gt; &lt;tt&gt;FINEST, FINER, FINE, CONFIG, INFO, WARNING, SEVERE&lt;/tt&gt;&lt;/li&gt;&lt;li&gt; &lt;tt&gt;ALL&lt;/tt&gt; and &lt;tt&gt;OFF&lt;/tt&gt; are defined values as well&lt;/li&gt;&lt;/ul&gt; Here is one style of using these &lt;tt&gt;Level&lt;/tt&gt;s in code, which may be modified as desired : &lt;ul&gt;&lt;li&gt; upon startup, use &lt;tt&gt;CONFIG&lt;/tt&gt; to log configuration parameters&lt;/li&gt;&lt;li&gt; during normal operation, use &lt;tt&gt;INFO&lt;/tt&gt; to log high-level "heartbeat" information&lt;/li&gt;&lt;li&gt; when bugs or critical conditions occur, use &lt;tt&gt;SEVERE&lt;/tt&gt;&lt;/li&gt;&lt;li&gt; debugging information might default to &lt;tt&gt;FINE&lt;/tt&gt;, with &lt;tt&gt;FINER&lt;/tt&gt; and &lt;tt&gt;FINEST&lt;/tt&gt; used occasionally, according to taste.&lt;/li&gt;&lt;/ul&gt; There is flexibility in how logging levels can be changed at runtime, without the need for a restart : &lt;ul&gt;&lt;li&gt; simply change the configuration file and call &lt;tt&gt;&lt;a href="http://java.sun.com/javase/6/docs/api/java/util/logging/LogManager.html#readConfiguration%28%29"&gt;LogManager.readConfiguration&lt;/a&gt;&lt;/tt&gt;.&lt;/li&gt;&lt;li&gt; or, change the level in the body of your code, using the logging API ; for example, one might automatically increase the logging level in response to unexpected events&lt;/li&gt;&lt;/ul&gt; Levels are attached to these items : &lt;ul&gt;&lt;li&gt; an originating logging request (from a single line of code)&lt;/li&gt;&lt;li&gt; a &lt;tt&gt;&lt;a href="http://java.sun.com/javase/6/docs/api/java/util/logging/Logger.html"&gt;Logger&lt;/a&gt;&lt;/tt&gt; (usually attached to the package containing the above line of code)&lt;/li&gt;&lt;li&gt; a &lt;tt&gt;&lt;a href="http://java.sun.com/javase/6/docs/api/java/util/logging/Handler.html"&gt;Handler&lt;/a&gt;&lt;/tt&gt; (attached to an application)&lt;/li&gt;&lt;/ul&gt; The flow of execution for a particular logging request usually proceeds as follows : &lt;p&gt;&lt;tt&gt;logging request of some level is made to logger attached to current package&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;if the request level is too low for that package's logger {&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;   discard it&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;}&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;otherwise {&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;   cycle through all handlers {&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;      if the request level is too low for that handler {&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;         discard it&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;      }&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;      otherwise {&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;         log the request&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;      }&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;   }&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;}&lt;/tt&gt; &lt;/p&gt;&lt;p&gt;Here is an example of a logging configuration file : &lt;/p&gt;&lt;p&gt;&lt;tt&gt;# Properties file which configures the operation of the JDK&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;# logging facility.&lt;/tt&gt; &lt;/p&gt;&lt;p&gt;&lt;tt&gt;# The system will look for this config file, first using&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;# a System property specified at startup:&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;#&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;# &gt;java -Djava.util.logging.config.file=myLoggingConfigFilePath&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;#&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;# If this property is not specified, then the config file is&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;# retrieved from its default location at:&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;#&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;# JDK_HOME/jre/lib/logging.properties&lt;/tt&gt; &lt;/p&gt;&lt;p&gt;&lt;tt&gt;# Global logging properties.&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;# ------------------------------------------&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;# The set of handlers to be loaded upon startup.&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;# Comma-separated list of class names.&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;# (? LogManager docs say no comma here, but JDK example has comma.)&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;handlers=java.util.logging.FileHandler, java.util.logging.ConsoleHandler&lt;/tt&gt; &lt;/p&gt;&lt;p&gt;&lt;tt&gt;# Default global logging level.&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;# Loggers and Handlers may override this level&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;.level=INFO&lt;/tt&gt; &lt;/p&gt;&lt;p&gt;&lt;tt&gt;# Loggers&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;# ------------------------------------------&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;# Loggers are usually attached to packages.&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;# Here, the level for each package is specified.&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;# The global level is used by default, so levels&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;# specified here simply act as an override.&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;myapp.ui.level=ALL&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;myapp.business.level=CONFIG&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;myapp.data.level=SEVERE&lt;/tt&gt; &lt;/p&gt;&lt;p&gt;&lt;tt&gt;# Handlers&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;# -----------------------------------------&lt;/tt&gt; &lt;/p&gt;&lt;p&gt;&lt;tt&gt;# --- ConsoleHandler ---&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;# Override of global logging level&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;java.util.logging.ConsoleHandler.level=SEVERE&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter&lt;/tt&gt; &lt;/p&gt;&lt;p&gt;&lt;tt&gt;# --- FileHandler ---&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;# Override of global logging level&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;java.util.logging.FileHandler.level=ALL&lt;/tt&gt; &lt;/p&gt;&lt;p&gt;&lt;tt&gt;# Naming style for the output file:&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;# (The output file is placed in the directory&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;# defined by the "user.home" System property.)&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;java.util.logging.FileHandler.pattern=%h/java%u.log&lt;/tt&gt; &lt;/p&gt;&lt;p&gt;&lt;tt&gt;# Limiting size of output file in bytes:&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;java.util.logging.FileHandler.limit=50000&lt;/tt&gt; &lt;/p&gt;&lt;p&gt;&lt;tt&gt;# Number of output files to cycle through, by appending an&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;# integer to the base file name:&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;java.util.logging.FileHandler.count=1&lt;/tt&gt; &lt;/p&gt;&lt;p&gt;&lt;tt&gt;# Style of output (Simple or XML):&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter&lt;/tt&gt; &lt;/p&gt;&lt;p&gt;An application should likely centralize the naming policy for &lt;tt&gt;Logger&lt;/tt&gt;s, since switching naming styles becomes a simple edit in one method, instead of a large number of edits spread throughout the application. Reasons to alter the naming policy might include : &lt;/p&gt;&lt;ul&gt;&lt;li&gt; in a shared environment, adding an application name to the &lt;tt&gt;Logger&lt;/tt&gt; name can help distinguish one application's entries from others&lt;/li&gt;&lt;li&gt; adding application version information might be beneficial for debugging&lt;/li&gt;&lt;/ul&gt;  There is a common complaint with the JDK logging config file : a Handler cannot be  restricted to a specific Logger. That is, Handlers defined in the config file are  global, in the sense that they will be attached to &lt;em&gt;all&lt;/em&gt; Loggers. This is  particularly annoying in a server environment, since different applications will,  by default, output logging statements into the same file. &lt;em&gt;This behavior can be easily changed, but only by using the JDK logging API.&lt;/em&gt; Many would prefer to do this directly in the config file.  &lt;p&gt;Here is an example of using the logging API :&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;span class="keyword"&gt;package&lt;/span&gt; myapp.business;&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;import&lt;/span&gt; java.util.logging.*;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;/**&lt;br /&gt;* Demonstrate Java's logging facilities, in conjunction&lt;br /&gt;* with a logging config file.&lt;br /&gt;*/&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;public&lt;/span&gt; &lt;span class="keyword"&gt;final&lt;/span&gt; &lt;span class="keyword"&gt;class&lt;/span&gt; SimpleLogger {&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;public&lt;/span&gt; &lt;span class="keyword"&gt;static&lt;/span&gt; &lt;span class="keyword"&gt;void&lt;/span&gt; main(String argv[]) {&lt;br /&gt; SimpleLogger thing = &lt;span class="keyword"&gt;new&lt;/span&gt; SimpleLogger();&lt;br /&gt; thing.doSomething();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;public&lt;/span&gt; &lt;span class="keyword"&gt;void&lt;/span&gt; doSomething() {&lt;br /&gt; &lt;span class="comment"&gt;//Log messages, one for each level&lt;br /&gt;&lt;/span&gt;    &lt;span class="comment"&gt;//The actual logging output depends on the configured&lt;br /&gt;&lt;/span&gt;    &lt;span class="comment"&gt;//level for this package. Calls to "inapplicable"&lt;br /&gt;&lt;/span&gt;    &lt;span class="comment"&gt;//messages are inexpensive.&lt;br /&gt;&lt;/span&gt;    fLogger.finest(&lt;span class="literal"&gt;"this is finest"&lt;/span&gt;);&lt;br /&gt; fLogger.finer(&lt;span class="literal"&gt;"this is finer"&lt;/span&gt;);&lt;br /&gt; fLogger.fine(&lt;span class="literal"&gt;"this is fine"&lt;/span&gt;);&lt;br /&gt; fLogger.config(&lt;span class="literal"&gt;"this is config"&lt;/span&gt;);&lt;br /&gt; fLogger.info(&lt;span class="literal"&gt;"this is info"&lt;/span&gt;);&lt;br /&gt; fLogger.warning(&lt;span class="literal"&gt;"this is a warning"&lt;/span&gt;);&lt;br /&gt; fLogger.severe(&lt;span class="literal"&gt;"this is severe"&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt; &lt;span class="comment"&gt;//In the above style, the name of the class and&lt;br /&gt;&lt;/span&gt;    &lt;span class="comment"&gt;//method which has generated a message is placed&lt;br /&gt;&lt;/span&gt;    &lt;span class="comment"&gt;//in the output on a best-efforts basis only.&lt;br /&gt;&lt;/span&gt;    &lt;span class="comment"&gt;//To ensure that this information is always&lt;br /&gt;&lt;/span&gt;    &lt;span class="comment"&gt;//included, use the following "precise log"&lt;br /&gt;&lt;/span&gt;    &lt;span class="comment"&gt;//style instead :&lt;br /&gt;&lt;/span&gt;    fLogger.logp(Level.INFO, &lt;span class="keyword"&gt;this&lt;/span&gt;.getClass().toString(), &lt;span class="literal"&gt;"doSomething"&lt;/span&gt;, &lt;span class="literal"&gt;"blah"&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt; &lt;span class="comment"&gt;//For the very common task of logging exceptions, there is a&lt;br /&gt;&lt;/span&gt;    &lt;span class="comment"&gt;//method which takes a Throwable :&lt;br /&gt;&lt;/span&gt;    Throwable ex = &lt;span class="keyword"&gt;new&lt;/span&gt; IllegalArgumentException(&lt;span class="literal"&gt;"Some exception text"&lt;/span&gt;);&lt;br /&gt; fLogger.log(Level.SEVERE, &lt;span class="literal"&gt;"Some message"&lt;/span&gt;, ex);&lt;br /&gt;&lt;br /&gt; &lt;span class="comment"&gt;//There are convenience methods for exiting and&lt;br /&gt;&lt;/span&gt;    &lt;span class="comment"&gt;//entering a method, which are at Level.FINER :&lt;br /&gt;&lt;/span&gt;    fLogger.exiting(&lt;span class="keyword"&gt;this&lt;/span&gt;.getClass().toString(), &lt;span class="literal"&gt;"doSomething"&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt; &lt;span class="comment"&gt;//Display user.home directory, if desired.&lt;br /&gt;&lt;/span&gt;    &lt;span class="comment"&gt;//(This is the directory where the log files are generated.)&lt;br /&gt;&lt;/span&gt;    &lt;span class="comment"&gt;//System.out.println("user.home dir: " + System.getProperty("user.home") );&lt;br /&gt;&lt;/span&gt;  }&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;// PRIVATE //&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment"&gt;//This logger will inherit the config of its parent, and add&lt;br /&gt;&lt;/span&gt;  &lt;span class="comment"&gt;//any further config as an override. A simple style is to use&lt;br /&gt;&lt;/span&gt;  &lt;span class="comment"&gt;//all config of the parent except, perhaps, for logging level.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment"&gt;//This style uses a hard-coded literal and should likely be avoided:&lt;br /&gt;&lt;/span&gt;  &lt;span class="comment"&gt;//private static final Logger fLogger = Logger.getLogger("myapp.business");&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment"&gt;//This style has no hard-coded literals, but forces the logger&lt;br /&gt;&lt;/span&gt;  &lt;span class="comment"&gt;//to be non-static.&lt;br /&gt;&lt;/span&gt;  &lt;span class="comment"&gt;//private final Logger fLogger=Logger.getLogger(this.getClass().getPackage().getName());&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment"&gt;//This style uses a static field, but hard-codes a class literal.&lt;br /&gt;&lt;/span&gt;  &lt;span class="comment"&gt;//This is probably acceptable.&lt;br /&gt;&lt;/span&gt;  &lt;span class="keyword"&gt;private&lt;/span&gt; &lt;span class="keyword"&gt;static&lt;/span&gt; &lt;span class="keyword"&gt;final&lt;/span&gt; Logger fLogger =&lt;br /&gt;                  Logger.getLogger(SimpleLogger.&lt;span class="keyword"&gt;class&lt;/span&gt;.getPackage().getName());&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Example Run 1 , using the config file defined above : &lt;p&gt;&lt;tt&gt;&gt;java -Djava.util.logging.config.file=C:\Temp\logging.properties&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;-cp . myapp.business.SimpleLogger&lt;/tt&gt; &lt;/p&gt;&lt;p&gt;&lt;tt&gt;ConsoleHandler&lt;/tt&gt; is configured to show only &lt;tt&gt;SEVERE&lt;/tt&gt; messages : &lt;/p&gt;&lt;p&gt;&lt;tt&gt;Jan 8, 2003 10:43:47 AM myapp.business.SimpleLogger doSomething&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;SEVERE: this is severe&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;Jan 8, 2003 10:43:47 AM myapp.business.SimpleLogger doSomething&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;SEVERE: Some message&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;java.lang.IllegalArgumentException: Some exception text&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;        at myapp.business.SimpleLogger.doSomething(SimpleLogger.java:39)&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;        at myapp.business.SimpleLogger.main(SimpleLogger.java:13)&lt;/tt&gt; &lt;/p&gt;&lt;p&gt;While the &lt;tt&gt;FileHandler&lt;/tt&gt; shows &lt;tt&gt;ALL&lt;/tt&gt; that is sent to it : &lt;/p&gt;&lt;p&gt;&lt;tt&gt;Jan 8, 2003 10:43:46 AM myapp.business.SimpleLogger doSomething&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;CONFIG: this is config&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;Jan 8, 2003 10:43:47 AM myapp.business.SimpleLogger doSomething&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;INFO: this is info&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;Jan 8, 2003 10:43:47 AM myapp.business.SimpleLogger doSomething&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;WARNING: this is a warning&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;Jan 8, 2003 10:43:47 AM myapp.business.SimpleLogger doSomething&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;SEVERE: this is severe&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;Jan 8, 2003 10:43:47 AM class myapp.business.SimpleLogger doSomething&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;INFO: blah&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;Jan 8, 2003 10:43:47 AM myapp.business.SimpleLogger doSomething&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;SEVERE: Some message&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;java.lang.IllegalArgumentException: Some exception text&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt; at myapp.business.SimpleLogger.doSomething(SimpleLogger.java:39)&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt; at myapp.business.SimpleLogger.main(SimpleLogger.java:13)&lt;/tt&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Example Run 2, showing the &lt;tt&gt;ConsoleHandler&lt;/tt&gt; output, using the &lt;tt&gt;logging.properties&lt;/tt&gt; file which ships with the JDK, and which logs only &lt;tt&gt;INFO&lt;/tt&gt; level and above : &lt;/p&gt;&lt;p&gt;&lt;tt&gt;&gt;java -cp . myapp.business.SimpleLogger&lt;/tt&gt; &lt;/p&gt;&lt;tt&gt;Jan 8, 2003 10:52:31 AM myapp.business.SimpleLogger doSomething&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;INFO: this is info&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;Jan 8, 2003 10:52:31 AM myapp.business.SimpleLogger doSomething&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;WARNING: this is a warning&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;Jan 8, 2003 10:52:31 AM myapp.business.SimpleLogger doSomething&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;SEVERE: this is severe&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;Jan 8, 2003 10:52:31 AM class myapp.business.SimpleLogger doSomething&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;INFO: blah&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;Jan 8, 2003 10:52:31 AM myapp.business.SimpleLogger doSomething&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;SEVERE: Some message&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;java.lang.IllegalArgumentException: Some exception text&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;        at myapp.business.SimpleLogger.doSomething(SimpleLogger.java:39)&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;        at myapp.business.SimpleLogger.main(SimpleLogger.java:13)&lt;/tt&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-3967138362601979468?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.javapractices.com/topic/TopicAction.do;jsessionid=6F2762520167D26863791ABFC5BA3571?Id=143' title='Java Logging using java.util.logging'/><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/3967138362601979468/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=3967138362601979468' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/3967138362601979468'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/3967138362601979468'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2008/01/java-logging-using-javautillogging.html' title='Java Logging using java.util.logging'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-7306841424500378197</id><published>2007-11-12T16:26:00.000Z</published><updated>2008-01-15T16:18:03.904Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='weblog'/><category scheme='http://www.blogger.com/atom/ns#' term='tomcat'/><title type='text'>Enable logging remote host name is tomcat access log.</title><content type='html'>To enable remote host name to be logged in tomcat access log, in conf/server.xml, you have to do two things:&lt;br /&gt;&lt;br /&gt;1.&lt;br /&gt;&lt;br /&gt;&amp;lt;Service name="Catalina"&amp;gt;&lt;br /&gt;...&lt;br /&gt;&amp;lt;Connector port="8080" ... enableLookups="true"..&amp;gt;&lt;br /&gt;...&lt;br /&gt;&amp;lt;Service&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2.&lt;br /&gt;&lt;br /&gt;&amp;lt;Host name="localhost" ..&amp;gt;&lt;br /&gt;...&lt;br /&gt;&amp;lt;Valve className="org.apache.catalina.valves.FastCommonAccessLogValve"&lt;br /&gt;  directory="logs"  prefix="access_log." suffix=".txt"&lt;br /&gt;  pattern="combined" resolveHosts="true" rotatable="true" fileDateFormat="yyyy-MM-dd"/&amp;gt;&lt;br /&gt;...&lt;br /&gt;&amp;lt;/Host&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;In the access log, it will look like:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;host217-43-97-182.range217-43.btcentralplus.com - - [12/Nov/2007:16:39:48 +0000] "GET /styles/topmenu.css HTTP/1.1" 200 1184 "http://www.jetonrails.com" "&lt;br /&gt;Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.1)"&lt;br /&gt;&lt;br /&gt;The first part is the remote host name instead of remote IP address.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-7306841424500378197?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/7306841424500378197/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=7306841424500378197' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/7306841424500378197'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/7306841424500378197'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2007/11/enable-logging-remote-host-name-is.html' title='Enable logging remote host name is tomcat access log.'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-8848047606673982037</id><published>2007-11-09T12:12:00.000Z</published><updated>2007-11-09T12:35:51.192Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='JSTL'/><title type='text'>Escape xml in JSTL</title><content type='html'>For &amp;lt;c:out&amp;gt; in JSTL:&lt;br /&gt;&lt;br /&gt;&amp;lt;c:out value="&amp;lt;p&amp;gt;Hello&amp;lt;/p&amp;gt"/&gt;&lt;br /&gt;&lt;br /&gt;It will generate source code like:&lt;br /&gt;&lt;br /&gt;&amp; lt;p&amp; gt;hello&amp; lt;/p&amp; gt;&lt;br /&gt;&lt;br /&gt;And it will show the wording in the browser like:&lt;br /&gt;&lt;br /&gt;&amp;lt;p&amp;gt;Hello&amp;lt;/p&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Solution: put excapteXml="false" in.&lt;br /&gt;&lt;br /&gt;&amp;lt;c:out escapexml="false" value="&amp;lt;p&amp;gt;Hello&amp;lt;/p&amp;gt;"/&gt;&lt;br /&gt;&lt;br /&gt;It will generate source code like:&lt;br /&gt;&lt;br /&gt;&amp;lt;p&amp;gt;Hello&amp;lt;/p&amp;gt;&lt;br /&gt;&lt;br /&gt;And it will show the wording in the browser like:&lt;br /&gt;&lt;br /&gt;Hello&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-8848047606673982037?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/8848047606673982037/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=8848047606673982037' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/8848047606673982037'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/8848047606673982037'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2007/11/escape-xml-in-jstl.html' title='Escape xml in JSTL'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-8157613883558175398</id><published>2007-11-05T12:49:00.000Z</published><updated>2007-11-05T13:14:40.356Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='XPath'/><category scheme='http://www.blogger.com/atom/ns#' term='XSLT'/><title type='text'>Select Distinct Values in XML</title><content type='html'>For the xml file like below:&lt;br /&gt;&lt;pre style="border: 1px inset ; margin: 0px; padding: 6px; overflow: auto; width: auto; height: 162px;"&gt;&lt;br /&gt;&amp;lt;books&amp;gt&lt;br /&gt;  &amp;lt;book author="Kevin Williams" title="Professional XML 2.0" /&amp;gt;&lt;br /&gt;  &amp;lt;book author="Lewis Carroll" title="Alice in Wonderland" /&amp;gt;&lt;br /&gt;  &amp;lt;book author="Lewis Carroll" title="Through the Looking-Glass" /&amp;gt;&lt;br /&gt;&amp;lt;/books&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;If you want to select distinct author from it, then make sure you use: xslt 2.0, and SaxonBB parser (in OxygenXML for example)&lt;br /&gt;&lt;pre style="border: 1px inset ; margin: 0px; padding: 6px; overflow: auto; width: auto; height: 162px;"&gt;&lt;br /&gt;&amp;lt;xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&amp;gt;&lt;br /&gt;   &amp;lt;xsl:output method="xml" indent="yes" /&amp;gt;&lt;br /&gt;  &lt;br /&gt;   &amp;lt;xsl:template match="units"&amp;gt;&lt;br /&gt;           &amp;lt;xsl:for-each select="distinct-values(unit_instance/lev_code)"&amp;gt;&lt;br /&gt;       &amp;lt;xsl:value-of select="."/&amp;gt;&lt;br /&gt;            &amp;lt;/xsl:for-each&amp;gt;&lt;br /&gt;       &amp;lt;/xsl:template&amp;gt;&lt;br /&gt;   &amp;lt;/xsl:stylesheet&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-8157613883558175398?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/8157613883558175398/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=8157613883558175398' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/8157613883558175398'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/8157613883558175398'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2007/11/select-distinct-values-in-xml.html' title='Select Distinct Values in XML'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-6933511636338200779</id><published>2007-11-01T17:00:00.000Z</published><updated>2007-11-01T17:01:34.619Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='CSS'/><title type='text'>Link spans two lines.</title><content type='html'>If a link spans two lines and looks terrible, then use the following code in the CSS.&lt;br /&gt;&lt;br /&gt;line-height: 14pt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-6933511636338200779?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/6933511636338200779/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=6933511636338200779' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/6933511636338200779'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/6933511636338200779'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2007/11/link-spans-two-lines.html' title='Link spans two lines.'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-5367792046001503852</id><published>2007-09-13T16:33:00.000+01:00</published><updated>2007-09-13T16:37:06.816+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Accessibility'/><category scheme='http://www.blogger.com/atom/ns#' term='html'/><title type='text'>Website Skip Navigation</title><content type='html'>Refer to the link. Creating a "Skip Navigation" in the web site allows visual disabled people to use the &lt;a href="http://en.wikipedia.org/wiki/List_of_screen_readers"&gt;screen  reader&lt;/a&gt; to jump over the navigation links and directly to the content.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-5367792046001503852?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.jimthatcher.com/skipnav.htm' title='Website Skip Navigation'/><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/5367792046001503852/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=5367792046001503852' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/5367792046001503852'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/5367792046001503852'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2007/09/website-skip-navigation.html' title='Website Skip Navigation'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-1815602735366135524</id><published>2007-08-17T14:18:00.000+01:00</published><updated>2007-08-17T14:38:35.574+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>Retrieve a text file from a web address</title><content type='html'>&lt;span style="font-weight: bold;"&gt;Requirement:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Retrieve a text file from a web address and write it to a local file.&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px inset ; margin: 0px; padding: 6px; overflow: auto; width: auto; height: auto;"&gt;&lt;br /&gt;&lt;br /&gt;// Retrieve the web address from the property file, in which you can change the web address without changing the Java code&lt;br /&gt;&lt;br /&gt;Properties properties = new Properties();&lt;br /&gt;try {&lt;br /&gt;properties.load(new FileInputStream("file.properties"));&lt;br /&gt;} catch (IOException e){&lt;br /&gt;System.out.println("Can't fild file.properties");&lt;br /&gt;}&lt;br /&gt;String webAddress= properties.getProperty("webAddress");&lt;br /&gt;&lt;br /&gt;// Construct the url&lt;br /&gt;URL url = new URL(webAddress);&lt;br /&gt;&lt;br /&gt;// Establish the connection&lt;br /&gt;HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();&lt;br /&gt;&lt;br /&gt;// Retrieve the response status code&lt;br /&gt;int statusCode = httpURLConnection.getResponseCode();&lt;br /&gt;&lt;br /&gt;if (statusCode == 200){&lt;br /&gt;  // Create an empty file&lt;br /&gt;  File file = new File ("folderName" + "/" + "fileName" + ".extensionName");&lt;br /&gt;  if (file.exists()) {&lt;br /&gt;   file.delete();&lt;br /&gt;  }&lt;br /&gt;  // Create a buffered writer for output&lt;br /&gt;  BufferedWriter output = new BufferedWriter(new FileWriter(file, true));&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  // Create a buffered reader to retrieve content from the web address&lt;br /&gt;  BufferedReader reader = new BufferedReader(new InputStreamReader((InputStream)httpURLConnection.getContent()));&lt;br /&gt;&lt;br /&gt;  String lLine = "";&lt;br /&gt;&lt;br /&gt;  // Read web content line by line and write it to the output file    &lt;br /&gt;  while ((line = reader.readLine()) != null) {&lt;br /&gt;  output.append(line);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  // Close the buffered writer&lt;br /&gt;  output.close();         &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-1815602735366135524?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/1815602735366135524/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=1815602735366135524' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/1815602735366135524'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/1815602735366135524'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2007/08/retrieve-text-file-from-web-address.html' title='Retrieve a text file from a web address'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-3112039337715660710</id><published>2007-08-16T11:48:00.000+01:00</published><updated>2007-08-16T11:50:04.317+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vi'/><title type='text'>Vi: Search and Replace</title><content type='html'>&lt;b&gt;Search&lt;/b&gt; (Wraped around at end of file): &lt;pre&gt;  Search STRING forward :   / STRING.&lt;br /&gt; Search STRING backward:   ? STRING.&lt;br /&gt;&lt;br /&gt; Repeat search:   n&lt;br /&gt; Repeat search in opposite direction:  N  (SHIFT-n)&lt;br /&gt;&lt;/pre&gt; &lt;br /&gt; &lt;b&gt;Replace&lt;/b&gt;: Same as with &lt;cite&gt;sed&lt;/cite&gt;, Replace OLD with NEW:   &lt;pre&gt;&lt;br /&gt;First occurrence on current line:      :s/OLD/NEW&lt;br /&gt;&lt;br /&gt;Globally (all) on current line:        :s/OLD/NEW/g&lt;br /&gt;&lt;br /&gt;Between two lines #,#:                 :#,#s/OLD/NEW/g&lt;br /&gt;&lt;br /&gt;Every occurrence in file:              :%s/OLD/NEW/g&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-3112039337715660710?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.felixgers.de/teaching/emacs/emacs.html' title='Vi: Search and Replace'/><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/3112039337715660710/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=3112039337715660710' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/3112039337715660710'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/3112039337715660710'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2007/08/vi-search-and-replace.html' title='Vi: Search and Replace'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-611640357903476806</id><published>2007-08-10T15:49:00.000+01:00</published><updated>2007-08-10T16:05:17.093+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='svn'/><title type='text'>svn merge example</title><content type='html'>&lt;span style="font-weight:bold;"&gt;Problem Solving:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Merge code from one branch to the trunk. &lt;br /&gt;&lt;br /&gt;The release candidate server has the code from trunk. &lt;br /&gt;&lt;br /&gt;In release_candidate server's source code directory:&lt;br /&gt;&lt;br /&gt;svn merge --dry-run -r rev1:rev2 branch_url&lt;br /&gt;&lt;br /&gt;# rev1 is the revision number when first branch out from trunk&lt;br /&gt;# rev2 is the latest revision number from the branch&lt;br /&gt;&lt;br /&gt;svn merge -r rev1:rev2 branch_url&lt;br /&gt;&lt;br /&gt;svn status | grep "C "&lt;br /&gt;&lt;br /&gt;# see any conflicts after merge, "C" stands for conflict&lt;br /&gt;&lt;br /&gt;# for those conflict files, edit them to fix the conflict.&lt;br /&gt;&lt;br /&gt;# filename.working is the local copy (here is the trunk code)&lt;br /&gt;# filename.right is the latest from the branch&lt;br /&gt;# filename.left is the original from the brach when first branched out from trunk&lt;br /&gt;&lt;br /&gt;# happy&lt;br /&gt;&lt;br /&gt;svn resolved filename&lt;br /&gt;&lt;br /&gt;svn commit -m "commit rev1:rev2 branch_url"&lt;br /&gt;&lt;br /&gt;# commit the merged code to the trunk&lt;br /&gt;&lt;br /&gt;# done&lt;br /&gt;&lt;br /&gt;For more svn knowledge, please see &lt;a href="http://svnbook.red-bean.com/"&gt;SVN RedBook&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-611640357903476806?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/611640357903476806/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=611640357903476806' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/611640357903476806'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/611640357903476806'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2007/08/svn-merge-example.html' title='svn merge example'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-6150531963561247836</id><published>2007-08-10T14:47:00.000+01:00</published><updated>2008-01-15T16:19:04.466Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='sorting'/><title type='text'>Sorting Map</title><content type='html'>The following definition is from Java API.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;HashMap:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Hash table based implementation of the Map interface. This implementation provides all of the optional map operations, and permits null values and the null key. (The HashMap  class is roughly equivalent to Hashtable, except that it is unsynchronized and permits nulls.) This class makes no guarantees as to the order of the map; in particular, it does not guarantee that the order will remain constant over time.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;LinkedHashMap:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Hash table and linked list implementation of the Map interface, with predictable iteration order. This implementation differs from HashMap in that it maintains a doubly-linked list running through all of its entries. This linked list defines the iteration ordering, which is normally the order in which keys were inserted into the map (insertion-order). Note that insertion order is not affected if a key is re-inserted into the map. (A key k is reinserted into a map m if m.put(k, v) is invoked when m.containsKey(k) would return true immediately prior to the invocation.)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;TreeMap:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Red-Black tree based implementation of the SortedMap interface. This class guarantees that the map will be in ascending key order, sorted according to the natural order for the key's class (see Comparable), or by the comparator provided at creation time, depending on which constructor is used.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Problem Solving:&lt;/span&gt;&lt;br /&gt;One university department has three levels of courses, namely undergraduate, postgraduate taught, and postgraduate research to offer. The department wants to show these courses in alphabatical order within respective level of course. The order of the level should be: undergraduate, postgraduate taught, postgraduate research.&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px inset ; margin: 0px; padding: 6px; overflow: auto; width: auto; height: auto;"&gt;&lt;br /&gt;LinkedHashMap courseMap = new LinkedHashMap();&lt;br /&gt;TreeMap ugCourseTreeMap = new TreeMap();&lt;br /&gt;courseMap.put("UG", ugCourseTreeMap);&lt;br /&gt; &lt;br /&gt;TreeMap pgtCourseTreeMap = new TreeMap();&lt;br /&gt;courseMap.put("PGT", pgtCourseTreeMap);&lt;br /&gt;&lt;br /&gt;TreeMap pgrCourseTreeMap = new TreeMap();&lt;br /&gt;courseMap.put("PGR", pgrCourseTreeMap);&lt;br /&gt;&lt;br /&gt;// looping begins&lt;br /&gt;// courseName is a String&lt;br /&gt;// course is a class&lt;br /&gt;&lt;br /&gt;ugCourseTreeMap.put(courseName, course);&lt;br /&gt;pgtCourseTreeMap.put(courseName, course);&lt;br /&gt;pgrCourseTreeMap.put(courseName, course);&lt;br /&gt;&lt;br /&gt;// looping end&lt;br /&gt;&lt;br /&gt;Iterator it = ugCourseTreeMap.values().iterator();&lt;br /&gt;while(it.hasNext()) {&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/**************No need to do the following************&lt;br /&gt;/**************Because TreeMap is ordered*************&lt;br /&gt;ArrayList keysUG = new ArrayList();&lt;br /&gt;keysUG.addAll(ugCourseMap.keySet());&lt;br /&gt;Collections.sort(keysUG);&lt;br /&gt;&lt;br /&gt;ArrayList keysPGT = new ArrayList();&lt;br /&gt;keysPGT.addAll(pgtCourseMap.keySet());&lt;br /&gt;Collections.sort(keysPGT);&lt;br /&gt;  &lt;br /&gt;ArrayList keysPGR = new ArrayList();&lt;br /&gt;keysPGR.addAll(pgrCourseMap.keySet());&lt;br /&gt;Collections.sort(keysPGR);&lt;br /&gt;&lt;br /&gt;// Iteration example&lt;br /&gt;Iterator it = ugCourseMap.keySet().iterator();&lt;br /&gt;while (it.hasNext()) {&lt;br /&gt;..&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/**********************************************&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-6150531963561247836?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/6150531963561247836/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=6150531963561247836' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/6150531963561247836'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/6150531963561247836'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2007/08/sorting-map.html' title='Sorting Map'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-7694830768293671946</id><published>2007-08-10T09:53:00.000+01:00</published><updated>2007-08-10T09:56:59.658+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='UNIX'/><title type='text'>Search a keyword in a directory recursively</title><content type='html'>If you want to search a keyword in files of the current directory and its sub directories:&lt;br /&gt;&lt;br /&gt;$/usr/local/home/jet&gt;&lt;br /&gt;&lt;br /&gt;then do:&lt;br /&gt;&lt;br /&gt;find . | xargs grep whatever&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-7694830768293671946?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/7694830768293671946/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=7694830768293671946' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/7694830768293671946'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/7694830768293671946'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2007/08/search-keyword-in-directory-recursively.html' title='Search a keyword in a directory recursively'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-7135045423301325529</id><published>2007-08-08T09:52:00.000+01:00</published><updated>2007-08-08T09:55:07.114+01:00</updated><title type='text'>To Learn List</title><content type='html'>&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://www.eclipse.org/webtools/jsf/main.php"&gt;WTP + JSF&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://www.eclipse.org/webtools/dali/main.php"&gt;Dali + JPA&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://grails.codehaus.org/"&gt;Grails&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-7135045423301325529?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/7135045423301325529/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=7135045423301325529' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/7135045423301325529'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/7135045423301325529'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2007/08/to-learn-list.html' title='To Learn List'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-6740493005506928810</id><published>2007-08-06T13:42:00.000+01:00</published><updated>2007-08-06T13:51:01.786+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Accessibility'/><category scheme='http://www.blogger.com/atom/ns#' term='html'/><title type='text'>The use of Link in HTML</title><content type='html'>&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-6740493005506928810?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.htmlcodetutorial.com/document/_LINK.html' title='The use of Link in HTML'/><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/6740493005506928810/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=6740493005506928810' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/6740493005506928810'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/6740493005506928810'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2007/08/use-of-link-in-html.html' title='The use of Link in HTML'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-1168463989924614720</id><published>2007-08-06T12:10:00.000+01:00</published><updated>2007-08-06T12:15:16.866+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CSS'/><category scheme='http://www.blogger.com/atom/ns#' term='Accessibility'/><title type='text'>Can't add Alt in background image in CSS</title><content type='html'>When using background: url(/imagesource); in CSS, please be aware that there no way to add Alt text. Therefore, using normal html &lt;img src="imagesource" alt="text"/&gt; instead.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-1168463989924614720?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/1168463989924614720/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=1168463989924614720' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/1168463989924614720'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/1168463989924614720'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2007/08/cant-add-alt-in-background-image-in-css.html' title='Can&apos;t add Alt in background image in CSS'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-8478461426120563643</id><published>2007-08-03T11:01:00.000+01:00</published><updated>2008-01-15T16:19:34.486Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='UNIX'/><category scheme='http://www.blogger.com/atom/ns#' term='sed'/><title type='text'>Replacing string in multiple files without changing filenames.</title><content type='html'>&lt;pre style="border: 1px inset ; margin: 0px; padding: 6px; overflow: auto; width: auto; height: 162px;"&gt;#!/bin/sh&lt;br /&gt;&lt;div dir="ltr" style="text-align: left;"&gt;&lt;br /&gt;for file in /path/to/my/files/*&lt;br /&gt;do&lt;br /&gt;sed 's/stringA/stringB/g' $file &gt; $file.new&lt;br /&gt;mv $file.new $file&lt;br /&gt;done&lt;br /&gt;exit 0&lt;/div&gt;&lt;/pre&gt;&lt;br /&gt;Make the script executable&lt;br /&gt;$ chmod u+x foo.sh&lt;br /&gt;&lt;br /&gt;Then run it (assuming it's in the current directory)&lt;br /&gt;$ ./foo.sh&lt;br /&gt;&lt;br /&gt;For more sed examples, please have a look at the &lt;a href="http://www.ibm.com/developerworks/linux/library/l-sed1.html"&gt;IBM articles&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-8478461426120563643?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/8478461426120563643/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=8478461426120563643' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/8478461426120563643'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/8478461426120563643'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2007/08/replacing-string-in-multiple-files.html' title='Replacing string in multiple files without changing filenames.'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-5426992388851540007</id><published>2007-08-02T16:19:00.000+01:00</published><updated>2007-08-03T11:14:52.148+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WTP'/><title type='text'>WTP Tutorials - JavaServer Faces Tools Tutorial</title><content type='html'>Any Eclipse fans who want to learn JSF should have a look at this tutorial.&lt;br /&gt;&lt;br /&gt;Make sure you say "Hello World!" ;)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-5426992388851540007?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.eclipse.org/webtools/jsf/docs/tutorial/JSFTools_1_0_tutorial.html' title='WTP Tutorials - JavaServer Faces Tools Tutorial'/><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/5426992388851540007/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=5426992388851540007' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/5426992388851540007'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/5426992388851540007'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2007/08/wtp-tutorials-javaserver-faces-tools.html' title='WTP Tutorials - JavaServer Faces Tools Tutorial'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9333605.post-110847275739559327</id><published>2005-02-15T13:05:00.000Z</published><updated>2007-07-30T11:54:39.681+01:00</updated><title type='text'>Generic Thing Pattern</title><content type='html'>&lt;a href="http://photos1.blogger.com/img/21/3371/640/Generic%20Thing%20Pattern.1.jpg"&gt;&lt;img style="border: 1px solid rgb(0, 0, 0); margin: 2px;" src="http://photos1.blogger.com/img/21/3371/320/Generic%20Thing%20Pattern.1.jpg" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Generic Thing Pattern&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Hay (1996) introduced a powerful data model by 'extracting the essence of each thing in order to deal with it as more of an abstraction'.&lt;br /&gt;&lt;br /&gt;The context meaning for the diagram is:&lt;br /&gt;&lt;br /&gt;A 'Thing Type' (aka a type of a thing) has many 'Attributes'.&lt;br /&gt;A 'Thing' belongs to a 'Thing Type'.&lt;br /&gt;A 'Thing' has its values which is associated with 'Attibutes'&lt;br /&gt;&lt;br /&gt;Its conventions of thought has been influencing many database designers and researchers. Silverton (2001) expanded this to introduce a flexible People and Organisations pattern.&lt;br /&gt;&lt;br /&gt;A dynamic form creator, Horde Ulaform (2005), based on the 'Thing' pattern uses the 'Thing Type' and 'Attribute' to define the form and uses the 'Thing' and 'Value' for storage of form fields values. It is a robus application which allows for easy creation of forms, but lacks of the relationships between entities which is what the database's power about. Furthermore it doesn't store the historical data of form fields. In terms of version manangement, it only store the current values of form fields. So it won't be suitable for version management for form data storage.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Reference:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Hay D.C., 1996. &lt;a href="http://www.dorsethouse.com/books/dmp.html"&gt;&lt;span style="font-style: italic;"&gt;Data Model Patterns: Conventions of Thought&lt;/span&gt;&lt;/a&gt;.  &lt;span class="smallfont"&gt;&lt;/span&gt;New York: &lt;span class="smallfont"&gt;Doset House Publishing co., inc. &lt;/span&gt; &lt;span class="smallfont"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Silverston L, 2001. &lt;a href="http://www.amazon.com/exec/obidos/ASIN/0471380237/102-0149433-3520962"&gt;&lt;span style="font-style: italic;"&gt;The Data Model Resource Book. Volume 1: A Library of Universal Data Models for All Enterprise&lt;/span&gt;&lt;/a&gt;. Revised Edition. Canada: Wiley.&lt;br /&gt;&lt;span class="smallfont"&gt;&lt;/span&gt;&lt;br /&gt;Horde. 2005. &lt;span style="font-style: italic;"&gt;Ulaform&lt;/span&gt; [online]. Available from: &lt;a href="http://www.horde.org/ulaform/"&gt;http://www.horde.org/ulaform/&lt;/a&gt; [Accessed 15 February 2005].&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:8;"&gt;Posted by &lt;a href="http://www.hello.com/" target="ext"&gt;Hello&lt;/a&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9333605-110847275739559327?l=jetlet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jetlet.blogspot.com/feeds/110847275739559327/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9333605&amp;postID=110847275739559327' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/110847275739559327'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9333605/posts/default/110847275739559327'/><link rel='alternate' type='text/html' href='http://jetlet.blogspot.com/2005/02/generic-thing-pattern_15.html' title='Generic Thing Pattern'/><author><name>Jianfeng Tian - Jet</name><uri>http://www.blogger.com/profile/01691282196833839280</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_LMzsCH4-1v4/Sy_bDTbA0wI/AAAAAAAAAiE/EmV7D_JwSy8/s1600-R/120_218136_3.jpg'/></author><thr:total>0</thr:total></entry></feed>
