Keeping it Small and Simple

2008.03.11

Oh Derby! Dumb, dumb, dumb Derby.

Filed under: Java Programming — Tags: , , , , , , , , , , — Lorenzo E. Danielsson @ 16:35

I was playing around with Apache Derby today. You know, that database server that started life as Cloudscape, became Derby and is now included in the JDK. Yeah, that one. For Debian (Sid) users, it is available via a aptitude install sun-java6-javadb.

I had a little file I was trying to import, called cartoons.sql.

 1 /*
 2  * Here there be ‘toons!
 3  */
 4
 5 CONNECT ‘jdbc:derby:toonsdb;create=true’;
 6
 7 CREATE TABLE cartoons(
 8     cartoon_id INT NOT NULL PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
 9     cartoon VARCHAR(255) NOT NULL,
10     UNIQUE(cartoon)
11 );
12
13 INSERT INTO cartoons(cartoon) VALUES(‘Bugs Bunny’);
14 INSERT INTO cartoons(cartoon) VALUES(‘Daffy Duck’);
15 INSERT INTO cartoons(cartoon) VALUES(‘Tom the Cat’);
16 INSERT INTO cartoons(cartoon) VALUES(‘Jerry Mouse’);

So, I tried to import:

% java -cp /usr/lib/jvm/java-6-sun/db/lib/derby.jar:/usr/lib/jvm/java-6-sun/db/lib/derbytools.jar:. org.apache.derby.tools.ij  IJ ERROR: Unable to establish connection
ij> IJ ERROR: Unable to establish connection
ij>

Hm, weird. I started ij tried running all the commands manually and that worked fine. Then I found out that could call ij with the name of the file directly (that is without the redirection). This would echo all the commands.

% java -cp /usr/lib/jvm/java-6-sun/db/lib/derby.jar:/usr/lib/jvm/java-6-sun/db/lib/derbytools.jar:. org.apache.derby.tools.ij cartoons.sql                   
ij version 10.3
ij> /*
 * Here there be 'toons!
 */

CONNECT 'jdbc:derby:toonsdb;
IJ ERROR: Unable to establish connection
ij> create=true';

CREATE TABLE cartoons(
    cartoon_id INT NOT NULL PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
    cartoon VARCHAR(255) NOT NULL,
    UNIQUE(cartoon)
);

INSERT INTO cartoons(cartoon) VALUES('Bugs Bunny');
INSERT INTO cartoons(cartoon) VALUES('Daffy Duck');
INSERT INTO cartoons(cartoon) VALUES('Tom the Cat');
INSERT INTO cartoons(cartoon) VALUES('Jerry Mouse');
;
IJ ERROR: Unable to establish connection
ij>

Something is not right. I thought the comment should be discarded? So why do I see it in the output above? It doesn’t give any errors per se, but its presence there is disturbing. What happens if I remove the comment?

% java -cp /usr/lib/jvm/java-6-sun/db/lib/derby.jar:/usr/lib/jvm/java-6-sun/db/lib/derbytools.jar:. org.apache.derby.tools.ij cartoons.sql
ij version 10.3
ij> CONNECT 'jdbc:derby:toonsdb;create=true';
ij> CREATE TABLE cartoons(
    cartoon_id INT NOT NULL PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
    cartoon VARCHAR(255) NOT NULL,
    UNIQUE(cartoon)
);
0 rows inserted/updated/deleted
ij> INSERT INTO cartoons(cartoon) VALUES('Bugs Bunny');
1 row inserted/updated/deleted
ij> INSERT INTO cartoons(cartoon) VALUES('Daffy Duck');
1 row inserted/updated/deleted
ij> INSERT INTO cartoons(cartoon) VALUES('Tom the Cat');
1 row inserted/updated/deleted
ij> INSERT INTO cartoons(cartoon) VALUES('Jerry Mouse');
1 row inserted/updated/deleted
ij>

Go figure! The comment is not being parsed, but does not end in a ; so it causes errors when I try to CONNECT. How fucking stupid is that?

For those who want an embeddable database written in Java, look at HSQLDB.

Advertisements

2008.01.10

JBoss/Seam tutorial series

Filed under: Java Programming — Tags: , , , , , — Lorenzo E. Danielsson @ 23:54

It seems my good friend and brother Edem has begun a tutorial series on JBoss/Seam on his blog. If want to learn how to develop with JBoss/Seam, I think you should definitely check his blog out.

He kicked off a while ago with a post showing how to set up NeBeans 6.0 for Seam development. Just today he posted a second part where he gets into actual Seam development.

2007.06.06

Translating source code into a different language as practice

Filed under: Computer Programming, Java Programming — Lorenzo E. Danielsson @ 13:05

One of the things I encourage my programming students to do is to take open source programs and rewriting them in a different programming language, or using a different GUI toolkit. There are a number of benefits to this:

  1. The student learns to read somebody else’s code
  2. The student learns to analyze code in a language that is different from the one they are learning
  3. The student (hopefully) learns a few new programming techniques along the way
  4. It is yet another way to keep the student writing code
  5. It provides a bit of variation from the old “write a program that..”-type exercises.

It’s easy to say that this is a “passive” process, meaning the student simply just translates the code to “their own” programming language without reflecting much about what they are doing. That may be true for some people, but then again, some people go through an entire programming class without reflecting much on what they are doing.

Another thing is that a friend of mine raised the concern that programming languages sometimes differ in techniques and that if I am translating a C program into Java I might be learning “C-isms”. First of all, I don’t quite understand what is so wrong with “C-isms”. Secondly, it is your responsibility as a teacher/mentor to review their code and point out areas where they could improve the program.

Remember that at first the student’s primary concern is with getting the program running at all. It is only once they have been able to do succeed in that that they will start worrying about “making it look like a conventional Java program”. The following might be a rough sketch of this process.

  1. Translate the program straight off (leaving variable names exactly the same etc). At this stage, the students only concern is to get the program to compile (in the case of a compiled language) and run, with all the functionality of the original program intact.
  2. Next they begin to do things like renaming variables to suit the language. For example, if translating a C program to Java, you might want to rename a variable from x_axis to xAxis simply because that is a convention that most Java programmers follow.
  3. Then the student refines the code. In the case of translating from a non-object orient language to an object oriented one, this might involve moving parts of the application functionality out into classes, where that makes sense.

Translating a program from for example C to Java, or from using Qt to using Gtk is not some form of miracle solution that will turn everybody into a master programmer. But it is a way to let the people who are genuinely interested in programming to get some extra practice. That’s all. I find the exercise useful. I would love to hear what others think. Please leave your comments/experiences in the comments section.

Finally I will give a small example. Recently, I had a Java student who said he wanted to learn how to do graphics programming. So I helped him get a hold of some programs (mostly in C) and told him to start translating them into Java. To demonstrate it I took this program by CorTeX/Optimum and wrote it as a Java applet. You can see the result below (you will obviously need to create an HTML document to load the applet in order to see it in action).

  1 /*
  2  * "Flashouillis" for Java.
  3  *
  4  * Original C program written by corTeX/Optimum.
  5  *
  6  * Author: Lorenzo E. Danielsson <danielsson.lorenzo (AT) gmail DOT com>
  7  * Date created: 2007.04.21
  8  */
  9 
 10 import java.awt.Color;
 11 import java.awt.Graphics;
 12 import java.awt.Image;
 13 import javax.swing.JApplet;
 14 
 15 import static java.lang.Math.cos;
 16 import static java.lang.Math.sin;
 17 import static java.lang.Math.random;
 18 
 19 public class JFlash extends JApplet implements Runnable {
 20     private final int WIDTH = 500;
 21     private final int HEIGHT = 500;
 22     private final int DELAY = 10;
 23     private final int FLASH_MAX = 5000;         // Number of points.
 24     private final int G_ACC = 330;              // Acceleration (g).
 25 
 26     private Thread animation = null;            // Animation thread.
 27     private Graphics buffer = null;             // Back buffer for drawing.
 28     private Image image = null;
 29     private Flash[] flash = new Flash[FLASH_MAX];
 30     private int current;
 31     private float ax = 0.0F, ay = 0.0F, az = 0.0F;
 32 
 33     public void init() {
 34         image = createImage(WIDTH, HEIGHT);
 35         buffer = image.getGraphics();
 36 
 37         for (int i = 0; i < FLASH_MAX; ++i) {
 38             flash[i] = new Flash();
 39             flash[i].state = 0.0F;
 40         }
 41 
 42         current = 0;
 43     }
 44 
 45     public void paint(Graphics g) {
 46         buffer.setColor(Color.BLACK);
 47         buffer.fillRect(0, 0, WIDTH, HEIGHT);
 48 
 49         for (int i = 0; i < FLASH_MAX; ++i) {
 50             if (flash[i].state == 0 || flash[i].state >= 1)
 51                 continue;
 52 
 53             int x = (int)(flash[i].x + flash[i].vx * flash[i].state);
 54             int y = (int)(flash[i].y + flash[i].vy * flash[i].state
 55                     + (flash[i].state * flash[i].state) * G_ACC);
 56 
 57             if (x < 0 || x > WIDTH || y < 0 || y > HEIGHT)
 58                 continue;
 59 
 60             int red = (int)(flash[i].r * (1 - flash[i].state)) << 3;
 61             int green = (int)(flash[i].g * (1 - flash[i].state)) << 2;
 62             int blue = (int)(flash[i].b * (1 - flash[i].state)) << 3;
 63 
 64             if (red > 255) flash[i].r = 255;
 65             if (green > 255) flash[i].g = 255;
 66             if (blue > 255) flash[i].b = 255;
 67 
 68             buffer.setColor(new Color(red, green, blue));
 69             buffer.drawLine(x, y, x, y);
 70 
 71             flash[i].state += 0.007F;
 72         }
 73 
 74         g.drawImage(image, 0, 0, null);
 75     }
 76 
 77     public void run() {
 78         Thread thread = Thread.currentThread();
 79         while (animation == thread) {
 80             repaint();
 81 
 82             int x = (int)(WIDTH/2 + WIDTH/4 * (cos(ax+ay) + sin(ay-az)));
 83             int y = (int)(HEIGHT/2 + HEIGHT/4 * (sin(ax-ay+2*az)
 84                         + sin(ax+ax/2)));
 85 
 86             for (int j = 0; j < 40; ++j) {
 87                 float rd = (float)(2.0 * random() * Math.PI);
 88                 float vx = (float)(cos(rd));
 89                 float vy = (float)(sin(rd));
 90                 rd = (float)(50.0 + random() * 30.0);
 91                 vx *= rd;
 92                 vy *= rd;
 93 
 94                 flash[current].x = x + ((int)(random() * Integer.MAX_VALUE)
 95                         & 3);
 96                 flash[current].y = y + ((int)(random() * Integer.MAX_VALUE)
 97                         & 3);
 98 
 99                 flash[current].vx = vx;
100                 flash[current].vy = vy;
101                 flash[current].state = 0.01F;
102 
103                 flash[current].r = (int)(10 * cos(ax*6) + 20);
104                 flash[current].g = (int)(20 * cos(ay*5) + 40);
105                 flash[current].b = (int)(10 * cos(az*7) + 20);
106 
107                 ++current;
108                 if (current == FLASH_MAX)
109                     current = 0;
110             }
111 
112             ax += 0.05F;
113             ay += 0.03F;
114             az += 0.0441F;
115 
116             try {
117                 thread.sleep(DELAY);
118             } catch (Exception e) {}
119         }
120     }
121 
122     public void start() {
123         animation = new Thread(this);
124         if (animation != null)
125             animation.start();
126     }
127 
128     public void stop() {
129         if (animation != null)
130             animation = null;
131     }
132 
133     public void update(Graphics g) {
134         g.clipRect(0, 0, WIDTH, HEIGHT);
135         paint(g);
136     }
137 }
138 
139 class Flash {
140     public int x = 0, y = 0;
141     public int r = 0, g = 0, b = 0;
142     public float state = 0.0F;
143     public float vx = 0.0F, vy = 0.0F;
144 }
145 

So this obviously does quite a few things that look familiar to a C programmer but maybe less so to a person from a Java background. But the point is that Java does support the shift operators. I’m not sure if you gain anything performance-wise in Java by using the shift operators for multiplying and dividing, but it is not illegal to do so.

Now this is just a first iteration of the program. It works, and looks like the original when run. You could easily modify it to look “better” from a Java point of view.

2007.05.24

Dealing with Java exceptions in JRuby

Filed under: Java Programming, JRuby, Ruby Programming — Lorenzo E. Danielsson @ 16:32

As you may know already, JRuby gives you access to the Java class library, so that you can do things like write Swing applications in Ruby. Of course, that also means that your JRuby code needs to deal with the exceptions that various Java classes can throw.

Exception handling is similar in Ruby and Java, but there are a few small differences. If you know both Java and Ruby you already know that in Java we use try and catch whereas in Ruby we use begin and rescue. But the principle is the same. Any code that could throw and excpetion goes into a try (or begin) block. If an exception is thrown, execution moves to the corresponding catch (rescue) block.

But Java has two slightly different types of exceptions: “normal” exceptions and runtime exceptions. The difference is that if you call anything that can throw java.lang.Exception or one of its subclasses, then you must enclose that code in a try-catch block. So, for instance, the following code will not compile:

1 public class ForNameTest {
2     public static void main(String[] args) {
3         Class.forName("java.lang.String");
4     }
5 }

Trying to compile we get:

% javac ForNameTest.java
ForNameTest.java:3: unreported exception java.lang.ClassNotFoundException; must be caught or declared to be thrown
        Class.forName("java.lang.String");
                     ^
1 error

In Ruby, however, it is not required to put any code within a begin-rescue block (in other words, Ruby treats all exceptions as they were Java runtime exceptions). Here is the equivalent JRuby code:

1 #! /usr/local/bin/jruby -w
2 
3 require 'java'
4 
5 java::lang::Class.forName("java.lang.String")

This will run without any problems. Notice another thing. I have specified the fully qualified name of the Java Class class. The reason is simple. Both Ruby and Java contain a class called Class. If I don’t qualify it, JRuby will assume that I want to use the Ruby class, which does not contain a forName method. Keep that in mind when there is both a Ruby class and a Java class with the same name.

Also note that just because we don’t have to use a begin-rescue in Ruby doesn’t mean that it is not a good idea. On the contrary, you should use exception handling to trap errors and do something useful when they occur.

Apart from that, dealing with Java exceptions in JRuby is very straightforward. Look at the following example:

 1 #! /usr/local/bin/jruby -w
 2 
 3 require 'java'
 4 
 5 include_class 'java.lang.ClassNotFoundException'
 6 
 7 begin
 8   # This will work.
 9   java::lang::Class.forName("java.lang.String")
10 
11   # This will not.
12   java::lang::Class.forName("foo.Bar")
13 rescue ClassNotFoundException => e
14   $stderr.print "Java told me: #{e}n"
15 end

Simple, wasn’t it? The first call to forName is not problematic because java.lang.String is a valid class name. The second call will fail, because under normal circumstances we don’t have a foo.Bar class (unless you have added one).

2007.05.17

Creating a simple Swing application in JRuby

Filed under: Java Programming, JRuby, Ruby Programming — Lorenzo E. Danielsson @ 09:27

First of all, for those who may not know, JRuby is an implementation of the Ruby programming language in Java. In addition to being a Ruby interpreter, JRuby also integrates with the Java platform, so you can interact with your existing Java classes from JRuby.

Being implemented in Java, JRuby of course has full support for Unicode. It also supports the Bean Scripting Framework. Supposedly you can run Ruby on Rails with JRuby, although I have not yet tried doing so myself. For more information about JRuby, go to their web site.

For those who’d like to try it, I’ll give you a very simple Swing application. If you are a bit familiar with both Ruby and Java, then you’ll get into JRuby in no time.

 1 #! /usr/local/bin/jruby -w
 2 
 3 require 'java'
 4 
 5 include_class 'java.awt.event.ActionListener'
 6 include_class 'javax.swing.JButton'
 7 include_class 'javax.swing.JFrame'
 8 
 9 class ClickAction < ActionListener
10   def actionPerformed(event)
11     puts "Button got clicked."
12   end
13 end
14 
15 class MainWindow < JFrame
16   def initialize
17     super "JRuby/Swing Demo"
18     setDefaultCloseOperation JFrame::EXIT_ON_CLOSE
19 
20     button = JButton.new "Click me!"
21     button.addActionListener ClickAction.new
22     add button
23     pack
24   end
25 end
26 
27 MainWindow.new.setVisible true

There that should be it. Remember, this is Ruby, so there’s no need to call the file anything special, and no “only one public class per file” restriction.

So how do you run this program? First of all, you need to have JRuby installed, which I assume you have. I installed my copy into /usr/local/jruby. I then created a symlink from /usr/local/jruby/bin/jruby to /usr/local/bin/jruby. That way the JRuby interpreter behaves just like the “normal” Ruby interpreter.

Assuming you have saved your program as swingtest.rb, installed JRuby and created your symlink, you should just have to do the following:


% chmod +x swingtest.rb
% ./swingtest.rb

Simple, wasn’t it?

Update

As I was writing this post, I downloaded the latest version of JRuby and the code above no longer runs. It turns out that you can no longer extend an interface. You are affected if you get this error:


% jruby button.rb
button.rb:[13,19]:[326,432]: superclass must be a Class (#) given (TypeError)

Fortunately, it’s very simple to fix. Simply change the ClickAction class to look as follows:

class ClickAction
  include ActionListener

  def actionPerformed(event)
    puts "Button got clicked."
  end
end

Now it should run fine. Still simple.


Update 2007.05.17: fixed the code to work with JRuby-1.0RC2.

2007.05.12

Desktop integration in Java 6

Filed under: Java Programming — Lorenzo E. Danielsson @ 16:29

One of the new things in Mustang (Java 6) is that the Java platform now integrates better with the Desktop. That means, for instance, that Java can “figure out” the application associated with a particular file-type. It also means that you can write so-called panel applets in Java, but that may be the topic for another post. Here I will focus specifically only on getting Java to open your default application for a particular action or MIME type.

We are going to be using methods provided by java.awt.Desktop. You may want to read up on this class in your Java API documentation.

The first thing you need to do is find out if desktop integration is supported on the platform that the application is running on. So create the following simple program, called DesktopSupportPrinter.java:

 1 import java.awt.Desktop;
 2 
 3 import static java.awt.Desktop.isDesktopSupported;
 4 
 5 public class DesktopSupportPrinter {
 6     public static void main(String[] args) {
 7         if (isDesktopSupported())
 8             System.out.println("Desktop is supported.");
 9         else
10             System.out.println("Desktop is not supported.");
11     }
12 }

When you are done, compile and run the program. On my system (running Debian GNU/Linux I get the following output:

% java DesktopSupportPrinter
Desktop is supported.

Okay, so far so, good. Desktop integration is supported on my platform. If you instead get a message that desktop is not supported then the rest of this post won’t work for you. Sorry about that, go and bug Sun about it.

If you’ve already browsed through the API documentation for the class you will see that there are methods for checking whether specific aspects of the Desktop integration are supported. Let’s try that next:

 1 import java.awt.Desktop;
 2 import static java.awt.Desktop.isDesktopSupported;
 3 import static java.awt.Desktop.Action.BROWSE;
 4 import static java.awt.Desktop.Action.EDIT;
 5 import static java.awt.Desktop.Action.MAIL;
 6 import static java.awt.Desktop.Action.OPEN;
 7 import static java.awt.Desktop.Action.PRINT;
 8 
 9 public class DesktopSupportPrinter {
10     public static void main(String[] args) {
11         if (isDesktopSupported()) {
12             System.out.println("Desktop supported.");
13         } else {
14             System.out.println("There is no desktop support.");
15             System.exit(0);
16         }
17 
18         Desktop desktop = Desktop.getDesktop();
19 
20         if (desktop.isSupported(BROWSE))
21             System.out.println(" + Browser is supported.");
22         else
23             System.out.println(" - Browser is not supported.");
24 
25         if (desktop.isSupported(EDIT))
26             System.out.println(" + Editor is supported.");
27         else
28             System.out.println(" - Editor is not supported.");
29 
30         if (desktop.isSupported(MAIL))
31             System.out.println(" + Mail is supported.");
32         else
33             System.out.println(" - Mail is not supported.");
34 
35         if (desktop.isSupported(OPEN))
36             System.out.println(" + Open is supported.");
37         else
38             System.out.println(" - Open is not supported.");
39 
40         if (desktop.isSupported(PRINT))
41             System.out.println(" + Printing is supported.");
42         else
43             System.out.println(" - Printing is not supported.");
44     }
45 }
46 

When you are done, compile and run it to see what is supported on your platform. When I run it, I get the following results:

% java DesktopSupportPrinter
Desktop supported.
 + Browser is supported.
 - Editor is not supported.
 + Mail is supported.
 + Open is supported.
 - Printing is not supported.

I’m not sure what it means that my editor is not supported. I have Vim installed (and I have Gvim as well) and both my EDITOR and VISUAL environment variables are set, so I wonder..

But having Java tell you that a particular desktop action is supported is not enough. I’m not really sure about this, but I think it may be that Java only supports particular applications. Most actions fail by default on my system. Java cannot open my default (mailer) or my default browser (iceweasel). If the same happens to you, see below for a (partial) fix.

Well, back to the lesson. If you did as I told you earlier and opened up your API documentation, you will have noticed that the Desktop class contains a number of action methods: browse, edit(), mail(), open() and print(). What each one of these does should be pretty obvious. We can try one of the methods out. Let’s use the browse method to open the default web browser.

According to the API documentation, the browse method takes the URI of the location to open as an argument. So I wrote a program called BrowserLauncher, which opens up Google in your browser.

 1 import java.awt.Desktop;
 2 import java.io.IOException;
 3 import java.net.URI;
 4 
 5 import static java.awt.Desktop.isDesktopSupported;
 6 import static java.awt.Desktop.Action.BROWSE;
 7 
 8 public class BrowserLauncher {
 9     public static void main(String[] args) {
10         if (!isDesktopSupported()) {
11             System.err.println("No desktop support, aborting..");
12             System.exit(1);
13         }
14 
15         Desktop desktop = Desktop.getDesktop();
16 
17         if (!desktop.isSupported(BROWSE)) {
18             System.err.println("No browser support, aborting..");
19             System.exit(1);
20         }
21 
22         try {
23             desktop.browse(new URI("http://www.google.com"));
24         } catch (IOException e) {
25             e.printStackTrace();
26         }
27     }
28 }

When you are done, compile and try the program. If your browser is already running, it may be that the program opens up a new browser tab and opens Google’s search page in it. If things don’t work, then just keep reading.

Introducing Java to your preferred browser

As I mentioned above, the browse() method wasn’t working for me. I was just getting exceptions thrown. But I figured out how to fix it. Let’s look at what I did.

Check if there is a directory called .gconf in your home directory. Gconf is something that is very close to a Linux virus (installs itself even though you don’t want it). The directory holds a few files and directories. We need to edit specific files here. Here is the procedure I went through to get browsing to work on my system.

  1. Edit the files ~/.gconf/desktop/gnome/applications/browser/%gconf.xml and ~/.gconf/desktop/gnome/url-handlers/http/%gconf.xml. In each file replace any mention of epiphany with iceweasel (or whatever browser you use). Not sure if it is necessary to edit both files, but just to be on the safe side..
  2. Check for running instances of gconfd with ps ax | grep gconf. Kill them, if they exist
  3. Restart gconfd, with /usr/lib/libgconf2-4/gconfd-2 &

After doing this, the browse() method started working. I’m assuming that you apply a similar principle to get the mailer working as well, but as of yet, I haven’t found the file that contains that information yet. If you know where it is, please let me know. A comment will do fine.

I know this is a bit kludgy, but desktop support in Java is new, and I’m guessing that the developers at Sun were in a hurry to get it out the door. I’m hoping that this gets simplified in Java 7. It would be so simple to just let Java parse a text file, maybe called ~/.preffered-applications instead of some obscure XML files managed by an application that exists only on my system because it was a dependency of another package that I did choose to install.

Create a free website or blog at WordPress.com.