Main | Next page »

PDF/DOC/PPT in-browser preview bookmarklet

Nov 09 2009, 13:37 MSK |  [  Misc  ]

I've seen several PDF/DOC/PPT preview bookmarklets (which work by rewriting the links to go through docs.google.com), but all of them didn't quite work for me (mostly, because they didn't escape the links correctly).

So here is my version of bookmarklet, drag this link: “PDF preview” into your Bookmarks toolbar. Clicking on it will cause all the links to PDF/DOC/PPT documents on the current page to be changed to links which go to a preview in Google Docs.

One nifty feature of this bookmarklet is CiteSeerX support: finally you can preview a PDF of the paper in browser, instead of downloading it (CiteSeerX has an annoying feature of forcing you to download the PDFs)! Why, oh, why didn't I come up with this easy solution before?

Making anti-aliasing in Java work

Feb 17 2009, 12:45 MSK |  [  Java  ]

Today I had quite a bad (although, eventually successful) experience of trying to fix anti-aliasing in JDK. The problem is that it is not on by default (at least for those members of the fringe who use something slick like XMonad instead of monstrosities like Gnome) and to turn it on one needs to set the awt.useSystemAAFontSettings Java VM property to one of the supported values (e.g. gasp, or lcd).

Now, I'm not really keen on changing the code of every Java application I happen to run on my machine, nor can I add -Dawt.useSystemAAFontSettings=lcd to every Java command line (did they really mean it?!). I started to look for a method to set properties globally, and of course I found suggestions of using swing.properties file. In retrospect, that wasn't a smart thing to try: I wanted to set AWT property, not Swing one, so eventually (by reading JDK source code) I found out that Java wasn't loading all the properties from the file, only those few which it knew, and it was obscure about the one I needed.

Fast-forward several hours, I found out that there is another interesting file: accessibility.properties. Although JDK only sets the properties that thinks can appear in the file (which isn't very helpful), one of the properties there is really a big step towards the solution, its key is assistive_technologies. This property value is a class name which gets instantiated some time during AWT initialization. Now, if only we could create a class which sets the abominable anti-aliasing property when instantiated, it would solve the problem once and for all... Or would it?

We need one more piece of the puzzle: suppose we have the class compiled, how do we make JRE see it, so that it could load it. If JRE doesn't have it in its classpath, an AWTError would be thrown during assistive technologies initialization. Setting classpath on the command line is not going to help us: we specificially wanted to do without changing Java command lines. Setting CLASSPATH environment variable won't help either: as per java(1) man, if classpath is set on the command line, it overrides the CLASSPATH variable completely. And putting the class/jar file into JRE lib directory doesn't make it visible to the system classloader — bummer!

Good news: we have the JDK source code and if one knows what to look for, its usually not that hard to find. The thing I was looking for was the list of initial classpath elements. Actually, I could just append my anti-aliasing workaround class into rt.jar, but that's not very flexible. So I found the list, and after a list of JRE jars there was a directory: "classes/"! Since the search is done starting from the JRE home directory, I could just create the classes directory there and put my class there.

My workaround class code follows:

package hacks;

public class AntialiasingHack {
  public AntialiasingHack() {
    System.setProperty("awt.useSystemAAFontSettings", "lcd_hrgb");
  }
}

Contents of jre/lib/accessibility.properties (or ~/.accessibility.properties) file:

assistive_technologies=hacks.AntialiasingHack

PS: If you have a more clean solution (other than filing an RFE for a generic startup properties file loader, arguing that it won't make the system more insecure than it already is, and waiting for several yearsjiffies to get it actually implemented and delivered in the next version of JDK), please-please-pretty-please tell me!

Scala Puzzlers, part 2

Jul 24 2008, 14:51 MSD |  [  Scala  ]

This puzzler is very strange. I have not completely figured out what causes the described performance problem yet, but I guess that it is a bug in the JVM, or in Scala compiler, or both.

I tried myself at Google Code Jam Qualification round this year and there was a nice problem called Fly Swatter (unfortunately there's no direct link to the problem description, but you can find it by clicking the “Qualification Round” link on the GCJ Contest page). It's fairly simple and it didn't take long to write a working solution in Scala. My solution produced correct results for the small test dataset, then I downloaded the large dataset (once downloaded one has 8 minutes to submit the results back), and…

Performance problem puzzler

… I figured out that my program was horribly slow. I didn't expect the program to work that slow: during the 8 minutes I'd had less than 30 (of 99) results were produced. Only after 32 minutes I got the results, alas, too late. I knew that in the worst case I'd get something like 250000 iterations for each test case, where each iteration computed couple of arcsines and several square roots, but hey, computers are fast these days, and I knew I didn't screw up with the algorithm (there were some obvious ways of improvement, but I figured that it was not necessary to use them — the performance should have been fine without them).

Now, here's the deal: my slow Scala program follows at the bottom of the post (you can also download it). Try to figure out what's wrong with it and how you can improve it's speed by two orders of magnitude (I'm not kidding you — it takes 8.5 seconds to run now on the same laptop). One caveat though: run the compiled program using Java HotSpot Server VM (it is used by default on my laptop, and only the Server VM shows the problem, not the Client VM), e.g.:

% time ( cat C-large.in | java -server -cp .:$SCALA_HOME/lib/scala-library.jar FlySwatter )

Input data should be piped to standard input, use the C-large.in dataset to test the program.

Spoiler

If you're Martin Odersky (and you want to check if it is a bug in Scala compiler) or if you're just too lazy to spend your time to inspect the code, profile, get puzzled because you don't get any meaningful results from the profiling, and then give up, take a look at the fixed program (there's a comment at the top which describes what has been done). Prepare to be surprised!

Slow version

/*
 * This is a slow version of the FlySwatter program.
 * It performs poorly on Server VM.
 * Try to find out why!
 */
import java.io._

object FlySwatter extends Application {
  case class Square(x1: Double, y1: Double, side: Double) {
    val x2 = x1 + side
    val y2 = y1 + side

    def area = side*side

    def isValid = side > 0

    def contractBy(f: Double): Square = {
      if (2*f >= side) {
        Square(x1 + side/2, y1 + side/2, 0)
      } else {
        Square(x1 + f, y1 + f, side - 2*f)
      }
    }
  }

  case class Case(f: Double, rr: Double, t: Double, r: Double, g: Double)

  def parseData: Seq[Case] = {
    val in = new BufferedReader(new InputStreamReader(System.in))
    def readCase: Case = {
      def readWords: Seq[String] = in.readLine.split(' ').filter(_.length > 0)

      val caseData = readWords.map(_.toDouble)
      Case(caseData(0), caseData(1), caseData(2), caseData(3), caseData(4))
    }

    val numCases = in.readLine.toInt
    val cases = for (i <- (1 to numCases).force) yield readCase
    cases
  }

  def calculateProbability(c: Case): Double = {
    def pointInCircle(x: Double, y: Double, r: Double): Boolean = {
      x*x + y*y < r*r
    }
    def squareAndCircleIntersectionArea(s: Square, r: Double): Double = {
      // calculates the definite integral from a to b of sqrt(r^2-x^2) dx
      def integrateCirclePart(a: Double, b: Double, r: Double): Double = {
        def i(x: Double): Double = x*Math.sqrt(r*r - x*x)/2 + r*r/2 * Math.asin(x/r)
        i(b)-i(a)
      }
      assert(s.x1 > 0 && s.y1 > 0)
      assert(r > 0)

      if (s.isValid) {
        val lowerLeftInCircle = pointInCircle(s.x1, s.y1, r)    // using lazy vals for these four booleans
        val upperLeftInCircle = pointInCircle(s.x1, s.y2, r)    // makes the program run ~25% slower,
        val lowerRightInCircle = pointInCircle(s.x2, s.y1, r)   // however real performance hit is probably lower
        val upperRightInCircle = pointInCircle(s.x2, s.y2, r)   // because the measurement precision is quite low

        val area: Double = (lowerLeftInCircle, upperLeftInCircle,
                    lowerRightInCircle, upperRightInCircle) match {
          case (false, _, _, _) => 0                                // square is outside of the circle
          case (true, _, _, true) => s.area                         // whole square is in the circle
          case (true, false, false, false) =>                       // single corner is in the circle
            val x = Math.sqrt(r*r - s.y1*s.y1)
            integrateCirclePart(s.x1, x, r) - (x-s.x1)*s.y1
          case (true, true, false, _) =>                            // left side of the square is in the circle
            integrateCirclePart(s.y1, s.y2, r) - (s.y2-s.y1)*s.x1
          case (true, false, true, _) =>                            // bottom side of the square is in the circle
            integrateCirclePart(s.x1, s.x2, r) - (s.x2-s.x1)*s.y1
          case (true, true, true, false) =>                         // 3 corners of the square are in the circle
            val x = Math.sqrt(r*r - s.y2*s.y2)
            (x-s.x1)*(s.y2-s.y1) + integrateCirclePart(x, s.x2, r) - (s.x2-x)*s.y1
        }
        assume(area >= 0)
        area
      } else {
        0 // empty square
      }
    }

    assert(c.g + 2*c.r > 0)
    val maxI = Math.ceil((c.rr - c.t - c.r)/(c.g + 2*c.r)).toInt
    val squares = for {
      i <- 0 until maxI; j <- 0 until maxI // until method creates a lazy list, thus we get a lazy list of Squares in the end
      x1 = c.r + i*(c.g + 2*c.r)
      y1 = c.r + j*(c.g + 2*c.r)
    } yield Square(x1, y1, c.g).contractBy(c.f)

    val squaresAndCircleIntersectionArea =
      (0.0 /: squares.map(squareAndCircleIntersectionArea(_, c.rr - c.t - c.f)))((a: Double, b: Double) => a+b)

    val flyIsSafeProb = squaresAndCircleIntersectionArea / (Math.Pi * c.rr * c.rr / 4)
    1-flyIsSafeProb
  }

  val cases = parseData
  for (i <- 0 until cases.length) {

    val prob = calculateProbability(cases(i))
    System.out.printf("Case #%1$d: %2$.6f\n", Array[Object](new java.lang.Integer(i+1), new java.lang.Double(prob)))
  }
}

Enjoy!

Scala puzzlers, part 1

Jul 18 2008, 04:17 MSD |  [  Scala  ]

I participated in the ICFP Contest this year. We decided to use Scala, and one of the reasons for using it was that we wanted to try the language out in a real-world stressful development project. There were four of us, and at least two of us (including me) had some experience with Scala. I'd been playing with the language for quite a while, and had a fair understanding of how to write programs in it. I'll probably post some write-up about ICFPC later.

During the contest we hit some trouble spots with the language, and lack of experience played some cruel tricks on us. This post is partly inspired by this experience. So, here we go, Scala puzzlers!

Puzzler #0: Weak typing

Consider the following code:

sealed abstract case class Msg
case class SaveTheWorld(from: String) extends Msg
case class FeedTheCat(name: String) extends Msg
case class GoToSleep extends Msg

object Thespian extends Actor {
  def act = {
    loop {
      react {
        case SaveTheWorld(threat) => println("Saving the world from the " + threat)
        case FeedTheCat(cat) => println("Feeding " + cat)
        case GoToSleep() => println("Zzzzz...")
        case Die(msg) => prinln(msg); exit 
      }
    }
  }
}

object WeakTyping extends Application {
  Thespian.start

  Thespian ! FeedTheCat("Panther")
  Thespian ! SaveTheWorld("Jabberwock")
  Thespian ! GoToSleep

  Thespian ! Die("The fair Ophelia! Nymph, in thy orisons be all my sins remember'd.")
}
Everything looks pretty simple, however there's a line missing in the output:
Feeding Panther
Saving the world from the Jabberwock
The fair Ophelia! Nymph, in thy orisons be all my sins remember'd.

The reason for this is that GoToSleep is not an object of type Msg, it is a function, which returns an instance of the case class GoToSleep when it is executed. You're not doing anything illegal when you're sending a function to the actor, so the compiler isn't going to stop you. And since parentheses are optional in a 0-argument method call, it's easy to forget to put the parentheses in case class instantiation.

There is another way to screw up: instead of matching on GoToSleep() one could try to pattern-match on GoToSleep in the react block.

A good way to solve this problem once and for all is to always use case objects instead of parameterless case classes. That way you won't need the parentheses and unless you have an apply method in your case object, compiler wouldn't allow you to use them.

Puzzler #1: val vs def

This one is quite obvious, but sometimes you can get caught on it during the refactoring.

def someEntity = new Entity(...)
val a = doSomething(someEntity)
val b = doSomethingElse(someEntity)

If doSomething and doSomethingElse expect to get the same object as an argument, you'd get a problem. It can be much more subtle if there is some method call instead of the explicit class instantiation in the first line. Again, it is easy to get confused because the parentheses are not required for 0-argument functions.


I have at least two more puzzlers and they are a little more involved. I'll try to publish them as soon as I get enough sleep (it's 4am already).

PS: If you know some Scala puzzlers, please send them to me, and I'll add them to the blog. Alternatively, publish them in your blog and be sure to send me the link!

Final Mercurial repositories of JDK7

Dec 06 2007, 10:52 MSK |  [  Java  ]
ivan@adagio:~/work % time hg fclone http://hg.openjdk.java.net/jdk7/jdk7/
[.]
requesting all changes
adding changesets
adding manifests
adding file changes
added 2 changesets with 26 changes to 26 files
26 files updated, 0 files merged, 0 files removed, 0 files unresolved

[corba]
requesting all changes
adding changesets
adding manifests
adding file changes
added 2 changesets with 1369 changes to 1369 files
1369 files updated, 0 files merged, 0 files removed, 0 files unresolved

[hotspot]
requesting all changes
adding changesets
adding manifests
adding file changes
added 2 changesets with 2895 changes to 2895 files
2895 files updated, 0 files merged, 0 files removed, 0 files unresolved

[jaxp]
requesting all changes
adding changesets
adding manifests
adding file changes
added 2 changesets with 1973 changes to 1973 files
1973 files updated, 0 files merged, 0 files removed, 0 files unresolved

[jaxws]
requesting all changes
adding changesets
adding manifests
adding file changes
added 2 changesets with 2307 changes to 2307 files
2307 files updated, 0 files merged, 0 files removed, 0 files unresolved

[jdk]
requesting all changes
adding changesets
adding manifests
adding file changes
added 2 changesets with 16527 changes to 16527 files
16527 files updated, 0 files merged, 0 files removed, 0 files unresolved

[langtools]
requesting all changes
adding changesets
adding manifests
adding file changes
added 2 changesets with 2974 changes to 2974 files
2974 files updated, 0 files merged, 0 files removed, 0 files unresolved

hg fclone http://hg.openjdk.java.net/jdk7/jdk7/  51.62s user 11.27s system 9% cpu 10:32.51 total

Yes, now you can really start working on your own fixes for JDK and be able to get them into the official repositories if they are that good. See also this post on Mark Reinhold's blog.

Enough said! Go get the JDK! :-)

OpenJDK Mercurial repositories are open

Nov 02 2007, 17:26 MSK |  [  Java  ]

Finally, we have the Mercurial repositories of JDK7 out in the open. They are still EXPERIMENTAL (yeah, in capitals), which means that these repositories (and their clones) are going to become invalid (totally unrelated to the repositories which would be used) in a couple of weeks, but you can still try to set up your environment and development process (if any) using them. Again, please don't do any real work on the clones of these repositories, the changesets you'd have probably would be useless when these repositories become officially open.

Here is a short instruction to get started with hacking the JDK. I assume that you have Mercurial set up. The build instructions here should work for Debian GNU/Linux (this is what I use on my laptop), however I don't promise anything :-) It should be relatively easy to do the same thing on Ubuntu (I doubt there are any differences other than the available package names/versions). It may require more work on other flavors of Linux. Still, if you have some problem building the JDK, you can ask me and I'll try to help you investigate (and, hopefully, fix) the problem.

Prerequisites

I'll assume that you have the following things set up and working:

  • JDK 6
  • Mercurial
  • GCC (>= 4.0)
  • Ant (>= 1.6.3)
  • FindBugs (>= 1.1)
  • GNU make
  • …and lots of other required libraries (see the README files for more info)

Getting the sources

Create the directory where you're going to have your repositories.

/home/ivan/work% mkdir openjdk
/home/ivan/work% cd openjdk

If you have the newer Mercurial with the forest extension, you can simply do

/home/ivan/work/openjdk% hg fclone http://hg.openjdk.java.net/jdk7/MASTER/
but if you don't, just follow the instructions below.

First, clone the master repository

/home/ivan/work/openjdk% hg clone http://hg.openjdk.java.net/jdk7/MASTER/

Clone all the other repositories into the MASTER repository:

/home/ivan/work/openjdk% cd MASTER
/home/ivan/work/openjdk/MASTER% for i in corba hotspot jaxp jaxws jdk langtools; hg clone http://hg.openjdk.java.net/jdk7/MASTER/$i/

After getting the sources, download the binary plugs from the OpenJDK download site and install them (run java -jar <downloaded-plugs-jar>) into some directory (I installed them in openjdk directory which I created above).

GCC 4.2 peculiarities

Now, if you are going to use GCC 4.2 or newer to build the JDK, you'll need to apply the patch to the HotSpot source before you continue. GCC 4.2 is more pedantic than the older ones and doesn't allow one to cast literal strings to char *, now you can only cast to const char * (which makes a lot of sense if you want to minimize the possibility of having nasty bugs which are hard to track). However the patch is a bit hackish: I use const_cast in a couple of places because it is the quickest and least intrusive fix I can provide there. This compilation issue should be addressed separately in JDK7 code-base (maybe in next build?).

First, download the patch, say, to /tmp/const_strings.patch. Now you have two choices: either use patch tool to apply the patch to the hotspot sources

/home/ivan/work/openjdk/MASTER/hotspot% patch -p1 < /tmp/const_strings.patch
or use the Mercurial Queues (the preferred way)
/home/ivan/work/openjdk/MASTER/hotspot% hg qinit
/home/ivan/work/openjdk/MASTER/hotspot% hg qimport /tmp/const_strings.patch
/home/ivan/work/openjdk/MASTER/hotspot% hg qpush const_strings.patch
You can read more about Mercurial Queues in this excellent tutorial (I suggest reading the other chapters too).

Setting up the environment

Build scripts use some environment variables to figure out what tools to use, where the JDK is, how many build threads should work concurrently, etc. You can either export these environment variables manually (like it is shown below) or create a script which sets the variables and executes the GNU make.

Here is what I did manually in shell:

% export LANG=C
% export ANT_HOME=/usr/share/ant 
% export FINDBUGS_HOME=~/work/findbugs-1.2.1 
% export ALT_BINARY_PLUGS_PATH=~/work/openjdk/openjdk-binary-plugs
% export ALT_BOOTDIR=/usr/local/java/jdk1.6.0
Fix the paths according to where you have the things installed. Then run make sanity and inspect the log. Fix the variables, run make sanity. Fix again, … I think you got it.

Although it isn't immediately clear from make sanity output and from the README files, you'd need to export one more variable: ALT_JDK_IMPORT_PATH, and according to the Glossary for JDK builds it should point to the path with a recent build of the same version of JDK we are building. Actually, it is a bug in the corba build files, and hopefully it would be fixed when the repositories are officially rolled out.

Building the JDK

Run make and go have a lunch :-)

Oh, you might want to have a tea first, just to be able to fix some minor problem that breaks the build in your case.

For reference: it took ~ 55 minutes to build the JDK on my 2Ghz laptop. The build directory size is 1.1Gb, although it may take more than that during the build (I didn't bother to measure).

Post-scriptum

Kudos to Kelly O'Hair and the JDK team, the build process now is very easy compared to what we had a little more than a year ago.

Remote access “life hack”

Oct 21 2007, 15:50 MSD |  [  Life hack  ]

Suppose that every time when you log in to some (possibly remote) machine using ssh you need to recall the path of some important directory, or that you want to be reminded to do something once you log in the next time. I recently found that this is a very usual scenario for me (because I ssh a lot and my memory is already stuffed with lots of things). So I invented a simple solution.

I added the following lines to my .zshrc file in my home directory:

if [ -f ~/.motd ]; then
  echo ----------------------------------------------------------
  cat ~/.motd
  echo ----------------------------------------------------------
fi
which simply cat's the contents of the .motd file whenever I log in. Now, if I want to be reminded of something, I can do
$ echo RTJ binaries are here: /net/xxx/yyy/zzz/nightly-build/build-abc/arch/bin >> ~/.motd
and the next time I log in, I'd get a message from which I can copy the useful path. It is also useful for setting up the reminders like “feed the cat, you lazy sod!”, although there is a risk for a cat to starve if you need to work at a single host without logging in for a long time.

You can simply remove a file once the validity of the notification expires or edit it using your favorite text editor to change/remove the bits of the contents.

Managing GlassFish server using JRuby

Apr 22 2007, 22:14 MSD |  [  JRuby  ]

If you are a developer writing an application which is inteneded to run on a GlassFish server, you are likely to do a lot of deployment work on your development/test servers. That's just the kind of work I do. And although I don't need to recreate the entire domains very often, I have to do that occasionally, and the process of configuring the application server domain through the web administration console is a pain, especially when you need to go through several wizards to create all those connection pools and JDBC resources which your application needs, set the JVM start parameters, etc., and you need to set up several domains that way (hey, GlassFish developers, is there some standard way I can do that work during the deployment of the application automatically?). Having done that several times, I decided that writing some tool to do all the work for me makes a lot of sense.

I tried to use shell scripts which called a bunch of asadmin commands to configure the domain and deploy the applications, but that didn't work out quite well. And I had some strange problems with remote application deployment using asadmin, so I had to ssh to the remote server and do the work locally. I guess I could create the necessary infrastructure for asadmin approach to work, but I felt that the result would be quite ugly. And I remebered that I had learnt about another interesting possibility last summer, when I had been helping guys to update the JDK samples for the upcoming release of the JDK, that was JMX. I did play with JMX for some time in the fall, but it never had any useful application in my work. This time I decided to use JMX for some real problem which I had been having for such a long time — application server domain configuration.

There are lots of good things in Java, but there are also some things which one may find frustrating to deal with under certain circumstances. One of such things is code verbosity, which is very thwarting when you need to write some small tool or just find out how the API work. One of the solutions to the code verbosity problem is to use some scripting language which can call Java APIs: there are BeanShell, JRuby, Jython, Groovy, Rhino, and many more other nice scripting languages. I'm watching closely the improvements in JRuby since last summer and I find Ruby adorable, hence the choice of a scripting language for the task was easy for me.

Configuration of the JMX connection on the server

Before we start connecting to the application server, we need to know some basic information: server address, JMX port (8686 by default), administrator user name (‘admin’ by default), and whether the server accepts only secure JMX connections, or not. JMX secure connections are disabled by default in GlassFish developer profile and enabled in cluster profile. However, I suggest you enabling the security for the JMX connector even for the developer domains: thus you'd understand better how the secure connections work and you wouldn't have the problems when you decide to deploy your applications on the server which has the secure connections enabled.

Creating connection pools

There is not much information about GlassFish management using JMX on the internet, at least I had a lot of problems finding the important pieces of information, most of them were obtained by reading the GlassFish sources. There is the AMX Javadoc, but it doesn't help to understand, how one should use the API. I discovered that the best way to understand, how the things work, is to use jirb — the JRuby version of the Interactive Ruby — in a typical session I simply instantiated some Java objects, looked at their method names and tried to call them and see what comes out.

To call the Java code from JRuby script, you need to do

require 'java'
in your script. You can use the same code in jirb. See the ‘Calling Java from JRuby’ page for more information on how to interoperate with Java code. There are also some code samples in JRuby distribution which explain the basic things. Unfortunately, you cannot load jar files in your JRuby code (or in a jirb session) and then use the classes from the library, so to use the AMX API you need to set the classpath before calling jirb:
$ CLASSPATH=/opt/glassfish/lib/javaee.jar:/opt/glassfish/lib/appserv-ext.jar jirb
/opt/glassfish is my path to the installed GlassFish. Now you can require 'java' and follow the rest of this post.

Connecting to the server

To connect to the application server you need to instantiate the com.sun.appserv.management.client.AppserverConnectionSource class with the parameters describing your connection:

conn = AppserverConnectionSource.new(AppserverConnectionSource::PROTOCOL_RMI, host, port, user, password, tls_params, nil)
conn.getJMXConnector(false)
Parameter names are self-describing, with the exception of, maybe, tls_params — it is an instance of the com.sun.appserv.management.client.TLSParams class and it contains the security settings for your connection. If you are using insecure JMX connection on the server, you may pass nil (which is treated as null by JRuby, when you pass it as a parameter to some Java method) in place of tls_params.

If you are using secure JMX connections, you have two basic strategies: you may trust any certificate which the server sends you during the TLS handshake, or you may want to check that you have this certificate (or the certificte of the authority which signed it, if the certificate is not self-signed) in your trust-store. It is possible to implement different authentication strategies (e.g., asking the user, whether she trusts the given certificate), but it is out of the scope of this blog post.

To implement the first (trust any certificate) strategy, you can use the following code:

TLSParams = com.sun.appserv.management.client.TLSParams
TrustAnyTrustManager = com.sun.appserv.management.client.TrustAnyTrustManager

tls_params = TLSParams.new(TrustAnyTrustManager.getInstanceArray, nil)
To implement the second (use trust-store to check the certificate) strategy, you should read the trust-store file and create the respective trust-store manager:
TLSParams = com.sun.appserv.management.client.TLSParams
TrustStoreTrustManager = com.sun.appserv.management.client.TrustStoreTrustManager
X509TrustManager = javax.net.ssl.X509TrustManager

store = java.io.File.new(trust_store_file_name)
store_password = java.lang.String.new(trust_store_password).to_char_array
trust_managers = X509TrustManager[1].new(TrustStoreTrustManager.new(store, store_password))
tls_params = TLSParams.new(trust_managers, nil)

Hopefully, you're able to connect to the server now. To control the domain configuration, we need to obtain the DomainConfig object from the established connection:

domain_root = conn.domain_root
domain_config = domain_root.domain_config
Notice how Java integeration code in JRuby automatically creates the Ruby-style accessors for the getters and setters.

Creating a connection pool

Creation of a connection pool is simple:

pool = domain_config.createJDBCConnectionPoolConfig(pool_name, datasource_class, nil)
where pool_name is an identifier of the connection pool and datasource_class is the name of the Java class used as data source (e.g. oracle.jdbc.pool.OracleDataSource for Oracle database). Having that line executed you can even check in the server admin console that the respective conection pool was created.

Then you need to configure the created connection pool. The first thing you might want to configure is the “Resource Type”:

pool.res_type = 'javax.sql.DataSource' # other legal values are ‘javax.sql.XADataSource’
                                       # and ‘javax.sql.ConnectionPoolDataSource’
All parameters which are available from the server admin console can be set using the corresponding methods of the pool variable (which is a proxy of an instance of JDBCConnectionPoolConfig class).

Apart from setting the standard connection pool parameters you might want to pass some additional properties to the database driver (see the ‘Additional Properties’ tab on the connection pool configuration page in admin console). To do this, you need to call the set_property_value(key, value) method of the pool object.

When you are done, you can use web administration console to test the connection (using the “Ping” button on the connection pool configuration page). Probably you can do it from JRuby script directly — but I have not figured it out yet.

Creating a JDBC resource

Once you have a connection pool, you need a corresponding JDBC resource which you can use from your application. The creation of the JDBC resource is a two step process (and it was very hard to figure out the second step — I had to read quite a lot of GlassFish code to understand what's going on): first we create the resource configuration object and after that we associate the created object with all the server instances on which we want to be able to access it.

domain_config.createJDBCResourceConfig resource_name, pool_name,
    HashMap.new({com.sun.appserv.management.config.ResourceConfigKeys::ENABLED_KEY => true })
domain_config.server_config_map['server-instance'].create_resource_ref resource_name, true
The first line here creates the JDBC resource configuration object, and the second adds the resource reference to the ‘server-instance’ server configuration.

Wrapping it all up in a script

After I got everything working in jirb, I decided to write a script, which would read the connection pool definitions from the YAML file and create them on the given application server instance, see the link below. When started it would print the usage information, you can also see the YAML configuration files examples in the script comments right after the license text. Note that it is actually a shell script which wraps up a JRuby script: thus it is possible to set up CLASSPATH (and, optionally, various Java VM options) before the jruby execution. Because of this it probably would not work on Windows out of the box — you'd need to strip out the environment setup code and jruby invocation (and don't forget to remove the END_OF_SCRIPT line!). Having that done you'd need to set up the CLASSPATH manually and start the script using the jruby.

You can download the script here or see a nice syntax-highlighted version here.

PS: I'm looking forward to hear your suggestions about using JRuby (or other nice languages) to do the similarly routine tasks!