tag:blogger.com,1999:blog-81255742024-02-29T01:51:47.475+08:00SimplicitySimple solutions to the complicated worldTai Siew Joonhttp://www.blogger.com/profile/18120318644785572894noreply@blogger.comBlogger40125tag:blogger.com,1999:blog-8125574.post-29802135770590733972016-05-01T14:15:00.001+08:002021-10-12T09:45:46.140+08:00Lifesaver Snippets<h2>
Universal JDBC CLI Client</h2>
I work on the Unix/Linux boxes running Java application servers regularly. One of the problems I always face is that access to the server is restricted, yet occasionally I have the need to access the most protected resources of all - the database. Without direct access to the database server, all my GUI database client tools are useless. What is available to me is only the JVM in an SSH session.<br />
<br />
I find that, while I can't install any database tools on the servers without going through a lot of bureaucratic red tapes, I can usually make use of what is already available on the server to do my work. With only h2, the JDBC driver and some shell script, I am able to connect to the database and get the data I want. Here's how.<br />
<br />
First, put all the jar files into the same folder. You should at least have h2 and the JDBC driver in the folder. Create a script <code>h2shell</code>:<br />
<br />
<pre class="brush: bash">#!/bin/bash
CP=.
for j in *.jar; do
CP=$CP:$j
done
java -Xmx512m -classpath $CP org.h2.tools.Shell "$@"
</pre>
<br />
Make the script executable:<br />
<br />
<pre class="brush: bash">chmod +x h2shell
</pre>
<br />
Next, create a helper script with the database connection properties. Let's call the
script <code>mydb</code>:<br />
<br />
<pre class="brush: bash">#!/bin/bash
./h2shell -url url -user username -password password
</pre>
<br />
Make the script executable too:<br />
<br />
<pre class="brush: bash">chmod +x mydb
</pre>
<br />
You can now connect to the DB by running mydb:<br />
<br />
<pre class="brush: bash">./mydb
</pre>
<br />
<h2>
telnet substitute</h2>
Due to the security policy of one of my clients, they remove the telnet program from all of their servers. telnet is one of common tools to test network connectivity. I found a crude alternative by writing some Python scripts.<br />
<br />
<pre class="brush: python">import telnetlib
t = telnetlib.Telnet('some.host', port)
print t.read_eager()
t.write(message)
print t.read_all()
t.close()
</pre>
<br />
Besides <code>telnetlib</code>, Python has a lot of other wonderful modules such as <code>urllib</code>, <code>socket</code>.<br />Tai Siew Joonhttp://www.blogger.com/profile/18120318644785572894noreply@blogger.com0tag:blogger.com,1999:blog-8125574.post-89589736590300339482013-06-08T11:37:00.000+08:002016-05-01T15:07:47.584+08:00How to calculate MD5 as zero-padded hex string in Groovy?<pre class="brush: groovy">import java.security.MessageDigest
def digest = MessageDigest.getInstance("MD5")
def bytes = data.getBytes()
def md5 = digest.digest(bytes)
// Convert to hex, left-padded with 0 to 32 chars
def hex = new BigInteger(1, md5).toString(16).padLeft(32, "0")
</pre>
<br />
Gist: <a href="https://gist.github.com/sjtai/5733901" target="_blank">https://gist.github.com/sjtai/5733901</a>Tai Siew Joonhttp://www.blogger.com/profile/18120318644785572894noreply@blogger.com0tag:blogger.com,1999:blog-8125574.post-30022066687406104292013-01-22T21:26:00.002+08:002013-06-08T11:38:29.312+08:00How to invoke JavaScript in JMeter?A colleague complained that there is little documentation about how to invoke JavaScript in JMeter. Specifically, his problem was about how to use the session ID to compute a value to be passed to the server. After playing with JMeter for an hour, we managed to figure it out. This is how it works:<br />
<br />
Since the session ID (JSESSIONID) is set as a cookie, we only need to figure how to retrieve the cookie in JMeter and pass it to the JavaScript. The first step is to enable cookies in JMeter so that they are accessible by using variables. In jmeter.properties, set <code>CookieManager.save.cookie=true.</code><br />
<br />
Next, make sure you add a HTTP Cookie Manager to your Thread Group. Add a BSF PostProcessor and write your JavaScript in the text area provided. You can also externalize your script to a file and specify the file name in the text field above the text area. You can access the JSESSIONID cookie this way:<br />
<pre>var sid = "${COOKIE_JSESSIONID}";</pre>
<br />
To invoke a JavaScript function and set the return value as a variable:<br />
<pre>var val = compute(sid);
vars.put("someKey", val);</pre>
<br />
You can access the value later as <code>${someKey}</code>.Tai Siew Joonhttp://www.blogger.com/profile/18120318644785572894noreply@blogger.com0tag:blogger.com,1999:blog-8125574.post-18407986054456105512013-01-15T12:03:00.001+08:002013-01-15T12:03:36.345+08:00How to extract a range of lines from a large file?It is not advisable to use vi to view a large
file as on most system vi will create a swap file of similar size. It is
better to extract the lines of interest to another file. Say you want
to extract lines 20001 to 30000 from a log file. There are many ways to
accomplish that and I am going to show you 2 of them here.<br /><br /><b>sed (my preferred way)</b><br /><span style="font-size: x-small;"><span style="font-family: courier new,monospace;">sed -n -e '20001,30000p' log.txt > /tmp/log-small.txt</span></span><br /><span style="font-family: "Courier New",Courier,monospace;">-n</span> means don't print anything unless the p command is used. <span style="font-family: "Courier New",Courier,monospace;">-e</span> means execute the following expression (those inside '....'). <span style="font-family: "Courier New",Courier,monospace;">20001,30000p</span> means for lines 20001 to 30000 inclusive, execute the command p, which prints them to the console.<br />
<div>
<br /></div>
<div>
<b>the head & tail way</b><br /></div>
<div>
<span style="font-family: courier new,monospace;">head -30000 log.txt | tail -10000 > /tmp/log-small.txt</span></div>
<div>
<br /></div>
<div>
The head command will output lines 1 to 30000 and pipe to tail which will print the last 10000 lines, i.e. lines 20001 to 30000.<br /></div>
As you can see, the head & tail way requires some mental arithmetics and so it is not my preferred way.Tai Siew Joonhttp://www.blogger.com/profile/18120318644785572894noreply@blogger.com0tag:blogger.com,1999:blog-8125574.post-69537302168893902812013-01-09T12:34:00.000+08:002013-01-09T12:34:12.834+08:00How to find out Solaris version number?Depending on what information you want, the following commands will provide different information about a Solaris server:
<br />
<ul>
<li>cat /etc/release</li>
<li>showrev</li>
<li>uname -a </li>
</ul>
Tai Siew Joonhttp://www.blogger.com/profile/18120318644785572894noreply@blogger.com0tag:blogger.com,1999:blog-8125574.post-27196512352094710422013-01-05T22:28:00.000+08:002013-01-05T22:28:38.402+08:00How to Get IP Address from MAC<p>One way to get the IP address of a remote host in the same subnet given a MAC address is by using the "arp -an" command. However, this will only work if the we have previously connected to the remote host.</p>
<p>With the help of nmap, we can find out the IP address. For example, the command below will scan the 10.1.1.0/24 subnet with nmap. After the scan we search through the output of arp. If the remote host that we are searching for is up, its MAC address will be displayed together with its IP address.
<pre>
$ nmap -sP 192.168.0.0/24 > /dev/null
$ arp -an | grep -i "12:34:56:78:90:ab"
? (192.168.0.105) at 12:34:56:78:90:ab [ether] on wlan0
</pre>
</p>
Tai Siew Joonhttp://www.blogger.com/profile/18120318644785572894noreply@blogger.com0tag:blogger.com,1999:blog-8125574.post-88236411341544802042012-10-27T23:37:00.000+08:002012-10-27T23:39:03.927+08:00The amazing date command<div><div>I use the Linux date command regularly. Normally I use it to format current date, e.g.
<pre>date +"%Y-%m-%d"</pre>
Yesterday, while writing a backup script, I found out that the command also understands simple English. E.g.
<pre class="prettyprint">
date +"%Y-%m-%d %H:%M:%S" --date "yesterday"
date +"%Y-%m-%d %H:%M:%S" --date "-7days"
date +"%Y-%m-%d %H:%M:%S" --date "-7days 00:00:00"
date +"%Y-%m-%d %H:%M:%S" --date "2 weeks ago"
</pre>
This helps when I want a date that represents, say, 3pm yesterday.</div></div>Tai Siew Joonhttp://www.blogger.com/profile/18120318644785572894noreply@blogger.com0tag:blogger.com,1999:blog-8125574.post-85127986973458564662012-10-23T13:08:00.001+08:002012-10-27T23:34:44.505+08:00log4j Configuration TipsHere are some of the tips/mistakes/solutions that I stumbled upon while configuring log4j. I am making a note for myself in case I need them in the future.<br />
<br />
<b>Variables.</b> If you use PropertyConfigurator to configure logging, you can use the ${...} notation in the configuration file. E.g. in log4j.properties:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">log4j.appender.A1.File=${user.home}/log/app.log</span><br />
<br />
The catch is you can only use System variables defined in java.lang.System.<br />
<br />
<b>Layout pattern.</b><br />
<ul>
<li>To indicate EOL, use %n, not \n.</li>
<li>%-5p is better than %6p as the log level will be left-aligned and you save 1 character per message.</li>
<li>%5t doesn't do what you want it to do, just use %t.</li>
</ul>
<br />
<b>NDC.</b> Although the use of NDC is discouraged, I find that, when used properly, it helps in troubleshooting. E.g. in the MDB's onMessage(), you can push some unique identifier to the NDC by using NDC.push(s). For example, transaction number, account number, customer number, etc. The value will appear if you also add %x in the pattern. Remember to call NDC.remove() before your return from the MDB. Pattern:<br />
<br />
<pre class="prettyprint">
NDC.push(id);
try {
...
}
finally {
NDC.pop();
if (NDC.getDepth() == 0) {
NDC.remove();
}
}
</pre>
<br />
<b>Logger syntax.</b><br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">log4j.logger.some.package=INFO,appender</span><br />
<br />
<br />
<b>Additivity syntax.</b><br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">log4j.additivity.some.package=false</span><br />
<br />
Note that some web sites write log4j.some.package.additivity=false but PropertyConfigurator is looking for the prefix log4j.additivity.<br />
<br />
<b>log4j.properties & log4j.xml in the same folder.</b> I noticed that when both files are found in the same folder, log4j.properties seems to have priority than the XML file unless your code specifically looks for log4j.xml.<br />
<br />
<b>Class name.</b> Don't use %c because full class names are usually very long. Don't use %c{1} because you can't tell which package the class is in. I suggest you try %c{2}, which prints the last 2 components of the full class names, e.g. util.Date.Tai Siew Joonhttp://www.blogger.com/profile/18120318644785572894noreply@blogger.com0tag:blogger.com,1999:blog-8125574.post-42588389093311694652012-08-30T10:14:00.001+08:002012-08-30T10:14:53.328+08:00How to check available memory in Solaris?There are many ways to check available memory in Solaris. One of the commands is:
<pre>prtconf | grep Memory</pre>
Tai Siew Joonhttp://www.blogger.com/profile/18120318644785572894noreply@blogger.com0tag:blogger.com,1999:blog-8125574.post-35096606196886464112009-08-31T17:15:00.006+08:002011-03-31T21:26:23.008+08:00The Linux cut commandcut is one of the lesser-known commands in the same category of tools such as grep, awk and sed. Nevertheless, I find it more convenient than the other tools in some circumstances. Let's say I have the following lines with ":" as the field delimiter:<br /><pre>abc:12:DEF<br />ghi:3a4:JKLM<br />opqr:56b:STUV<br /></pre><br /><br />To print out the values in the second column, I can use the command<br /><pre class="brush: bash"><br />cut -d: -f2<br /></pre><br />where -d: specifies that the field delimiter is ":", -f2 specifes that the field to print is 2.<br /><br />If the delimiter is the space character, the command will become<br /><pre class="brush: bash"><br />cut -d\ -f2<br /></pre><br />Notice there are 2 space characters after the backslash. The backslash will escape the space character that follows it.Tai Siew Joonhttp://www.blogger.com/profile/18120318644785572894noreply@blogger.com0tag:blogger.com,1999:blog-8125574.post-73493994783833173392009-05-06T12:51:00.005+08:002009-05-06T13:05:09.366+08:000.0 Is A BigDecimal In Groovy!When you are so used to the convenience offered by Groovy and Grails, sometimes you are caught by simplicity itself.<br /><br />I created a domain class recently:<br /><pre class="brush: groovy"><br />class Foo {<br /> ...<br /> double price<br /><br /> static constraints = {<br /> price(min: 0.0)<br /> }<br />}<br /></pre><br /><br />Boom! The application failed to run with the error message:<br /><pre class="brush: bash; light: true"><br />Parameter for constraint [min] of property [value] of class [class Foo] <br />must be the same type as property: [double]<br /></pre><br /><br />The cause of the problem is that I declared price to be a double, but 0.0 is a BigDecimal in Groovy. To fix the problem, change the value to 0.0d. I found the answer from this <a href="http://www.nabble.com/bug-on-double-type-field-with-min-constraints-td8946047.html#a8946047">thread</a>.Tai Siew Joonhttp://www.blogger.com/profile/18120318644785572894noreply@blogger.com0tag:blogger.com,1999:blog-8125574.post-25109111459762238642009-05-06T12:23:00.004+08:002009-05-06T12:45:34.646+08:00When Class.forName() Can't Find The Domain ClassI was trying to use reflection to create a domain class:<br /><pre class="brush: groovy"><br />try {<br /> def clazz = Class.forName(domainClassName)<br /> def obj = clazz.newInstance()<br />}<br />catch (ClassNotFoundException ex) {<br /> ...<br />}<br /></pre><br /><br />To my surprise, I caught <code>ClassNotFoundException</code> at line 2. After searching for a while, I found an explanation in this <a href="http://www.nabble.com/Really-Weird-Class.forName-Error-td20650734.html" target="external">thread</a>. Burt Beckwith explained that classes loaded without a ClassLoader will not resolve dynamically added classes such as the domain classes. He suggested to use the other variant:<br /><pre class="brush: groovy"><br />try {<br /> def clazz = Class.forName(domainClassName, true, Thread.currentThread().contextClassLoader)<br /> obj = clazz.newInstance()<br />}<br />catch (ClassNotFoundException ex) {<br /> ...<br />}<br /></pre><br />Thanks for the tips, Burt.Tai Siew Joonhttp://www.blogger.com/profile/18120318644785572894noreply@blogger.com0tag:blogger.com,1999:blog-8125574.post-84712655504500092102009-05-02T23:22:00.013+08:002009-05-05T15:05:10.859+08:00Self-printing Groovy ProgramIt always amazes me when I read about how people write a C program that print itself. The self-printing program, or more formally, <a href="http://en.wikipedia.org/wiki/Quine_(computing)" target="external">quine</a>, prints out its source code.<br /><br />Having used Groovy for a while, I wonder if there is any self-printing Groovy program on the Internet. After some googling around, I found some Java programs on this <a href="http://www.nyx.net/~gthompso/self_java.txt" target="external">page</a>. After spending about 15 minutes, I came up with what I think is the first self-printing Groovy program to date. I used Bertram Felgenhauer's 2nd example as my starting point. Here is my version in Groovy (the code is written in one line):<br /><pre class="brush: groovy; toolbar: false; gutter: false"><br />class S{public static void main(a){def s="class S{public static void main(a){def s=;char c=34;println(s.substring(0,41)+c+s+c+s.substring(41));}}";char c=34;println(s.substring(0,41)+c+s+c+s.substring(41));}}<br /></pre><br />See if you can make it shorter.<br /><br /><h3>Updates</h3><br /><br /><a href="http://www.blogger.com/profile/05227615949751525227">Chrigel</a> suggested the removal of "public". I have to adjust the parameter to substring() too. Here is a shorter version (195 bytes):<br /><pre class="brush: groovy; toolbar: false; gutter: false"><br />class S{static void main(a){def s="class S{static void main(a){def s=;char c=34;println(s.substring(0,34)+c+s+c+s.substring(34));}}";char c=34;println(s.substring(0,34)+c+s+c+s.substring(34));}}<br /></pre><br /><br />paulk's version is 97 bytes:<br /><pre class="brush: groovy; toolbar: false; gutter: false"><br />def s="def s=;char c=34;println s[0..5]+c+s+c+s[6..-1]";char c=34;println s[0..5]+c+s+c+s[6..-1]<br /></pre><br /><br />paulk's 2nd version is 46 bytes:<br /><pre class="brush: groovy; toolbar: false; gutter: false"><br />s="s=%c%s%c;printf s,34,s,34";printf s,34,s,34<br /></pre><br /><br />paulk's 3rd version is 42 bytes. Keep going, paulk!<br /><pre class="brush: groovy; toolbar: false; gutter: false"><br />s='s=%c%s%1$c;printf s,39,s';printf s,39,s<br /></pre><br /><br /><a href="http://www.blogger.com/profile/12825144483682260459">Gavin Grover</a> found a 38-char solution at <a href="http://golf.shinh.org/p.rb?Quine">http://golf.shinh.org/p.rb?Quine</a>:<br /><pre class="brush: groovy; toolbar: false; gutter: false"><br />printf _='printf _=%c%s%1$c,39,_',39,_<br /></pre><br /><br />Are we approaching the limit?Tai Siew Joonhttp://www.blogger.com/profile/18120318644785572894noreply@blogger.com12tag:blogger.com,1999:blog-8125574.post-16938919506139468292009-04-20T11:17:00.008+08:002009-04-22T10:13:32.282+08:00Grails Quick ReferenceI have just finished version 1.1.0 of Grails Quick Reference. For your download convenience, here's the zip file containing the latest source of the quick reference: <a href="http://bitbucket.org/sjtai/grailsqr/get/tip.zip">http://bitbucket.org/sjtai/grailsqr/get/tip.zip</a>. The PDF can be downloaded from <a href="http://docs.codehaus.org/download/attachments/40788/grailsqr-1.1.0.pdf">here</a>.<br /><br /><a rel="license" href="http://creativecommons.org/licenses/by/2.5/my/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by/2.5/my/88x31.png" /></a><br /><span xmlns:dc="http://purl.org/dc/elements/1.1/" href="http://purl.org/dc/dcmitype/Text" property="dc:title" rel="dc:type">Grails Quick Reference</span> by <span xmlns:cc="http://creativecommons.org/ns#" property="cc:attributionName">Tai Siew Joon</span> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/2.5/my/">Creative Commons Attribution 2.5 Malaysia License</a>.Tai Siew Joonhttp://www.blogger.com/profile/18120318644785572894noreply@blogger.com3tag:blogger.com,1999:blog-8125574.post-39526236061822232642009-04-16T00:03:00.002+08:002009-04-16T00:10:14.979+08:00The Y292M problemIn about 292 million years from now, we will face the Year 292 Million problem in all our Java/Groovy programs. Luckily it falls on a Sunday, so I think the impact on business will be minimum.<br /><br />I use <code>new Date(Long.MAX_VALUE)</code> to calculate that date.Tai Siew Joonhttp://www.blogger.com/profile/18120318644785572894noreply@blogger.com0tag:blogger.com,1999:blog-8125574.post-65032204538566502752009-04-15T23:30:00.004+08:002009-04-15T23:55:18.713+08:00Groovy's groupBy and inject methods<h2>groupBy</h2><br /><br /><a href="http://blog.intelligrape.com/?p=33">Aman Aggarwal</a> blogged about a powerful method from the <code>java.util.Collection</code> class. The <code>groupBy</code> method converts a collection into a <code>Map</code> with the keys being returned by the closure passed to the method.<br /><br />Example:<br /><pre class="brush: groovy"><br />def map = invoices.groupBy { it.invoiceDate.format("MM/yyyy") }<br />map.each { k, v -><br /> println "There are ${v.size()} invoices in ${k}"<br />}<br /></pre><br /><br />Incidentally, the example above uses another cool function from <code>java.util.Date</code>: <code>format</code>. The method takes a date pattern (from the specification of <code>java.text.SimpleDateFormat</code>) and returns a <code>String</code>.<br /><br /><h2>inject</h2><br /><br />While writing about <code>groupBy</code>, I thought I might as well talk about the <code>inject()</code> method too. It is a method that is best explained with an example. If I want to add all the numbers from 1 until 10, i.e. 1 + 2 + 3 + 4 + ... + 10, I can do it in one line:<br /><pre class="brush: groovy"><br />def sum = (1..10).inject(0) { a, b -> a += b }<br /></pre><br />0 is passed as the initial value. In each iteration, the value from the last iteration is passed as <code>a</code> while the current value is passed as <code>b</code>. If we add a println statement, e.g.<br /><pre class="brush: groovy"><br />def sum = (1..10).inject(0) { a, b -><br /> println "${a} + ${b} = ${a + b}"<br /> a += b<br />}<br /></pre><br />The output will be:<br /><pre class="brush: bash"><br />0 + 1 = 1<br />1 + 2 = 3<br />3 + 3 = 6<br />6 + 4 = 10<br />10 + 5 = 15<br />15 + 6 = 21<br />21 + 7 = 28<br />28 + 8 = 36<br />36 + 9 = 45<br />45 + 10 = 55<br /></pre><br /><br />Another typical example is to calculate the product of a range of numbers. For example, to calculate the product of 1 to 10 (the factorial of 10):<br /><pre class="brush: groovy"><br />def product = (1..10).inject(1) { a, b -> a *= b }<br /></pre><br /><br />The result is the expected 3628800 (= 10!).Tai Siew Joonhttp://www.blogger.com/profile/18120318644785572894noreply@blogger.com4tag:blogger.com,1999:blog-8125574.post-12400152793705046112009-04-10T08:57:00.003+08:002009-04-10T09:16:13.391+08:00New find and findAll methods for String in Groovy 1.6.1In Ted Naleid's <a href="http://naleid.com/blog/2009/04/07/groovy-161-released-with-new-find-and-findall-regexp-methods-on-string/">blog</a>, he describes the patches to the String class that he contributed to the Groovy community recently. The patches have been released as Groovy <a href="http://groovy.codehaus.org/Download">1.6.1</a> on April 7, 2009.<br /><br />He listed the following new methods:<br /><ul><br /><li>eachMatch(Pattern pattern) { fullMatch, group1, ... -> ... }</li><br /><li>find(String regex)</li><br /><li>find(String regex) { fullMatch, group1, ... -> ... }</li><br /><li>find(Pattern pattern)</li><br /><li>find(Pattern pattern) { fullMatch, group1, ... -> ... }</li><br /><li>findAll(String regex)</li><br /><li>findAll(String regex) { fullMatch, group1, ... -> ... }</li><br /><li>findAll(Pattern pattern)</li><br /><li>findAll(Pattern pattern) { fullMatch, group1, ... -> ... }</li><br /></ul><br />In other words, the find/findAll methods now accepts a regular expression and the matching groups are passed to the closure.<br /><br />Thanks for the patches, Ted.Tai Siew Joonhttp://www.blogger.com/profile/18120318644785572894noreply@blogger.com1tag:blogger.com,1999:blog-8125574.post-2828763410427150332009-04-09T20:15:00.006+08:002009-04-09T20:26:37.740+08:00Worst Usability ExampleTo create a Windows service from the command line, one would normally use the sc command. I wasted almost half an hour today while settings Subversion's svnserve service. So I thought I had better document my ordeal.<br /><br />To start with, sc has the worst command line syntax that I have seen in my entire life as a software developer. The syntax to create a service for Subversion, type:<br /><pre class="brush: bash; toolbar: false"><br />sc create svn binPath= "c:\subversion\bin\svnserve.exe -r c:\repo" start= auto DisplayName= "Subversion Server" depend= Tcpip<br /></pre><br />Notice there is whitespace after the "=" character? No, it's not "start=auto". If you type that, sc will print out the command line syntax and the service is not created. Add in the space, you will have svnserve running as a Windows service.<br /><br />Can someone explain why the syntax is so weird?Tai Siew Joonhttp://www.blogger.com/profile/18120318644785572894noreply@blogger.com0tag:blogger.com,1999:blog-8125574.post-10744312722824557192009-04-05T17:59:00.007+08:002009-04-09T19:31:37.198+08:00A simple example of the power of polymorphismI often see codes written by the less experienced programmers that contain a lot of if/else blocks where they do something differently with different types of objects. For example,<br /><pre class="brush: java"><br />public class Coordinator {<br /><br /> public void doSomethingWithList(List list) {<br /> for (Object o : list) {<br /> if (o instanceof A) {<br /> A a = (A) o;<br /> doSomethingWithA(a);<br /> }<br /> else if (o instanceof B) {<br /> B b = (B) o;<br /> doSomethingWithB(b);<br /> }<br /> // and so forth for class C, D, E, F, ...<br /> }<br /> }<br />}<br /></pre><br />In the above codes, the current method is making all the coordination work as it determines what to do with different types of objects. By introducing a superclass or an interface, we can refactor the code to something more extensible, and you don't have to change the loop each time a new class is introduced.<br /><br />First, declare an interface (or a superclass that all the different types of objects will inherit from):<br /><pre class="brush: java"><br />public interface Foo {<br /> public void workWith(Coordinator coordinator);<br />}<br /></pre><br />Change types A, B, C, D, ... to implement this interface:<br /><pre class="brush: java"><br />public class A implements Foo {<br /> public void workWith(Coordinator coordinator) {<br /> // do something specific to the A class<br /> }<br />}<br /></pre><br />Change <code>Coordinator.doSomethingWithList()</code> to:<br /><pre class="brush: java"><br />public void doSomethingWithList(List<Foo> list) {<br /> for (Foo o : list) {<br /> o.workWith(this);<br /> }<br />}<br /></pre><br />You'll never have to change the loop again when you introduce new types. The Coordinator will invoke the <code>workWith()</code> method polymorphically since all implementations of <code>Foo</code> must define that method.Tai Siew Joonhttp://www.blogger.com/profile/18120318644785572894noreply@blogger.com0tag:blogger.com,1999:blog-8125574.post-63115354656596450842009-04-04T23:08:00.004+08:002009-04-09T19:28:46.879+08:00Testing Controllers That Are Protected By JSecurity PluginIt can be a challenge to write a test case to test an action that depends on the current user. For example, the list action only returns the records that is accessible by the current user.<br /><br />If you use the JSecurity Plugin, chances are you will use <code>SecurityUtils.getSubject()</code> to refer to the current user. If the user logs in through the login form provided by the plugin, the user name is stored as <code>SecurityUtils.getSubject().principal</code>. What we want to do is to find a way to inject the "current" user name during the test.<br /><br />This is how I did it. In FooController, I define <code>getSubject</code> and <code>list</code> like this:<br /><pre class="brush: groovy"><br />class FooController {<br /><br /> def getSubject = {<br /> return SecurityUtils.getSubject()<br /> }<br /><br /> def list = {<br /> def subject = getSubject()<br /><br /> // Restrict results in listing<br /> ...<br /> [fooInstanceList: results, fooInstanceListTotal: total]<br /> }<br />}<br /></pre><br />and the test:<br /><pre class="brush: groovy"><br />void testList() {<br /> FooController.metaClass.getSubject = { return [principal: 'user1'] }<br /> def ctrl = new FooController()<br /> ctrl.list()<br /> ...<br />}<br /></pre><br />In line 1, just before the FooController instance is created, the <code>getSubject</code> closure is modified to return a map that contains <code>principal</code> as the key. When the list action is invoked, the <code>getSubject()</code> method will return the map. That way, the listing will be restricted to the records which are accessible by the user <code>user1</code>.Tai Siew Joonhttp://www.blogger.com/profile/18120318644785572894noreply@blogger.com0tag:blogger.com,1999:blog-8125574.post-39691602178476309732009-04-01T17:34:00.002+08:002009-04-01T17:40:54.376+08:00How to rollback a transaction in a serviceThe Grails Framework Reference Documentation only mentions that a method in a service class can be set as transactional. However, it fails to mention how one should rollback a transaction.<br /><br />It is actually easier than I thought. If the method throws an exception, the transaction will rollback. Although you can perform multi-table updates in a controller, it is good practice to do it in a service method.Tai Siew Joonhttp://www.blogger.com/profile/18120318644785572894noreply@blogger.com0tag:blogger.com,1999:blog-8125574.post-78216313169119709822009-04-01T16:47:00.013+08:002009-04-06T09:09:20.312+08:00Difference between findAll and findAllByYou may have already known the obvious difference between the domain class findAll() and findAllByXXX() method. findAll() expects a query as the first parameter, followed by the parameter list and the pagination parameters whereas findAllByXXX() expects variable list of objects, ending with an optional map for pagination purpose.<br /><br />There is a small difference, and I got caught once by it.<br /><br />As findAll allows you to write the query anyway you want, which may include the "order by ... desc" fragment. Therefore, findAll() ignores the "sort" and "order" entry in the pagination map. This won't return a list of countries in descending order:<br /><pre class="brush: groovy"><br />def list = Country.findAll("from Country c where c.continent = ?",<br /> [ continent ],<br /> [sort: 'name', order: 'desc']);<br /></pre><br />To make it work, I did the following:<br /><pre class="brush: groovy">def sort = params.sort ?: 'name'<br />def order = params.order ?: 'asc'<br />def q = "from Country c where c.continent = ? order by ${sort} ${order}"<br />def list = Country.findAll(q, [ continent ], params)<br /></pre><br />The params is still passed in to the function because the max and offset parameters are used.<br /><br />If the query is simple enough like the query above, it is better to write:<br /><pre class="brush: groovy">def list = Country.findAllByContinent(continent, params)<br /></pre>Tai Siew Joonhttp://www.blogger.com/profile/18120318644785572894noreply@blogger.com0tag:blogger.com,1999:blog-8125574.post-40551827081392283292009-03-21T22:55:00.007+08:002009-04-09T20:34:09.494+08:00Integration test of Grails controllerThe general pattern to test a controller is:<br /><pre class="brush: groovy"><br />void testBar() {<br /> def ctrl = new FooController()<br /> def testParams = ...<br /> ctrl.params.putAll(testParams)<br /> ctrl.bar()<br /> ...<br />}<br /></pre><br /><br />Different outcomes are expected from the call to the action:<br /><br /><h3>Redirection</h3><br />If redirection is expected, the redirected URL can be obtained from <code>ctrl.response.redirectedUrl</code>. Keep in mind that unless <a href="http://jira.codehaus.org/browse/GRAILS-4270" target="external">GRAILS-4270</a> is resolved, you will have to make sure that the controller name is specified in the parameter list of <code>redirect()</code>. For example,<br /><pre class="brush: groovy"><br />def index = {<br /> redirect(action: 'list', params: params)<br />}<br /></pre><br />won't work. You need to change it to:<br /><pre class="brush: groovy"><br />def index = {<br /> redirect(controller: 'foo', action: 'list', params: params)<br />}<br /></pre><br /><br /><h3>A View Is Rendered</h3><br />If a view is expected, the parameters passed to <code>render()</code> is actually stored in Spring's <a href="http://static.springframework.org/spring/docs/2.5.x/api/org/springframework/web/servlet/ModelAndView.html" target="external">ModelAndView</a> object. E.g. if you have the following statement in your controller:<br /><pre class="brush: groovy; toolbar: false"><br />render(view: 'show', model: [ fooInstance: foo ])<br /></pre><br />You can access foo via:<br /><pre class="brush: groovy; toolbar: false"><br />def foo = ctrl.modelAndView.model.fooInstance<br /></pre><br /><br /><h3>Text Is Rendered Directly</h3><br />If the action renders some texts directly, the texts can be accessed by<br /><pre class="brush: groovy; toolbar: false"><br />def text = ctrl.response.contentAsString<br /></pre><br /><br /><h3>A Map Is Returned</h3><br />If a map is returned, as is the case for the scaffolded list action, you can access the map like this:<br /><pre class="brush: groovy; toolbar: false"><br />def map = ctrl.list()<br /></pre>Tai Siew Joonhttp://www.blogger.com/profile/18120318644785572894noreply@blogger.com1tag:blogger.com,1999:blog-8125574.post-51513132589334158422009-03-12T18:10:00.006+08:002009-04-06T09:14:34.816+08:00Groovy wrapper for Snipplr APII created a Groovy wrapper for <a href="http://snipplr.com/">Snipplr</a> API this afternoon. It is called, rather boringly, gsnipplr. I wanted to try out Groovy's XMLRPC module and use Maven to build the Groovy project. I threw in quite a comprehensive set of tests (IMO) and had a lot of fun playing with the testing code.<br /><br />A lot of ideas were taken from arcturus' <a href="http://www.ardeenelinfierno.com/wordpress/code/snipplrpy/">SnipplrPy</a>. Thanks for the great example!<br /><br />The source code is hosted at <a href="http://bitbucket.org/sjtai/gsnipplr">http://bitbucket.org/sjtai/gsnipplr</a>.<br /><br />To check out:<br /><pre class="brush: bash"><br />hg clone http://bitbucket.org/sjtai/gsnipplr<br /></pre>Tai Siew Joonhttp://www.blogger.com/profile/18120318644785572894noreply@blogger.com0tag:blogger.com,1999:blog-8125574.post-5831553508353299952009-02-19T10:14:00.005+08:002009-04-06T18:21:57.772+08:00Testing Ajax pages with WebTestI just learned that you need to add some delay to the test script after making an Ajax call. (Isn't it logical? Why didn't I think of that?).<br /><br />For example, assuming there is an <code>onChange</code> handler in the combo box, you should add a sleep step after <code>setSelectField</code>. Groovy code below:<br /><pre class="brush: groovy"><br />setSelectField(htmlId: 'foo', text: 'bar')<br />sleep(seconds: 5)<br />...<br /></pre>Tai Siew Joonhttp://www.blogger.com/profile/18120318644785572894noreply@blogger.com0