Wednesday, February 29, 2012

Upgrading Postgres Database to 9.1 Format After Upgrading to Fedora 16

After upgrading from Fedora 15 to Fedora 16, I noticed Postgres was no longer running, so I tried to start it up:
sudo systemctl status postgresql.service
This printed the error "Job failed. See system logs and 'systemctl status' for details." Inspecting /var/log/messages revealed:
Feb 29 12:51:39 jetengine postgresql-check-db-dir[4912]: An old version of the database format was found.
Feb 29 12:51:39 jetengine postgresql-check-db-dir[4912]: Use "postgresql-setup upgrade" to upgrade to version 9.1.
Feb 29 12:51:39 jetengine postgresql-check-db-dir[4912]: See /usr/share/doc/postgresql-9.1.2/README.rpm-dist for more information.
Feb 29 12:51:39 jetengine systemd[1]: postgresql.service: control process exited, code=exited status=1
Feb 29 12:51:39 jetengine systemd[1]: Unit postgresql.service entered failed state.
So I needed to upgrade to the new 9.1 format. I used the following command to check the current version of my database:
sudo cat /var/lib/pgsql/data/PG_VERSION
This returned "9.0".

To upgrade the database, I first needed to install the postgresql-upgrade package:

sudo yum install -y postgresql-upgrade
I then ran the following command to update the database:
sudo postgresql-setup upgrade
This command took a minute or two to complete. Once it was done, the database at /var/lib/pgsql/data/ was in 9.1 format, and the old 9.0 format database was saved to /var/lib/pgsql/data-old/ However, the upgrade tool did not copy over my old pg_hba.conf, so I had to do that myself:
sudo mv /var/lib/pgsql/data-old/pg_hba.conf  /var/lib/pgsql/data/pg_hba.conf
Now I was able to successfully start up Postgres 9.1:
sudo systemctl start postgresql.service

Friday, May 27, 2011

Making Links Work Right in a SmartGWT App on IE

The GUI of RHQ 4.0 and later is built upon SmartGWT. In many places in the SmartGWT app, we embedded raw HTML to render fragment links (e.g. #Inventory/Servers) to other places in the app. We used raw HTML, rather than widgets, for a few reasons:

  1. SmartGWT does not provide a link widget. GWT provides the HyperLink and InlineHyperLink widgets, but we try to avoid using non-SmartGWT widgets when possible to prevent layout issues or CSS issues caused by straying from the SmartGWT framework. A SmartGWT Label or HTMLFlow can be extended to simulate a link using a ClickHandler but it will not be rendered as an 'a' tag and so will not inherit the CSS styles used for 'a' tags and will not display the link's URL in the browser status bar when the user hovers over the link.
  2. Many of our links are inside ListGrid cells. There is no straightforward reliable way to embed arbitrary widgets in ListGrid cells. I tried using the mechanism http://www.smartclient.com/smartgwt/showcase/#grid_cell_widgets described here and encountered overflow and wrapping issues, which I was unable to overcome. The CellFormatter interface only supports returning a String, but that String can include HTML, so that's what we ended up using for cells that need to contain a link.
  3. For FormItems that need to contain links, CanvasItem can be extended in order to embed GWT HyperLink widgets, but using a StaticTextItem with HTML embedded in its value is more straightforward.
Unfortunately, we noticed that clicking on any of our raw HTML fragment links in IE caused a full page refresh, which is not at all desirable in a GWT app, which is intended to be pure AJAX. Further investigation revealed that this is a longstanding quirk (aka bug) in IE; rather than simply generating a history event for the URL with the updated fragment, it sends an unnecessary request for the URL to the server. If you use the GWT HyperLink widget, GWT uses some JavaScript fanciness involving iframes to circumvent the IE bug and make fragment links work properly. However, since we were using raw HTML for all the links in the RHQ GUI, this magic was not there for us. Converting all our HTML links would be a ton of work and was simply not a viable option for links in ListGrid cells for the reasons described above, so we needed to find a way to execute GWT's magic when any of our raw HTML links were clicked. The answer ended up being to add a native preview event handler that intercepts browser click events and executes the magic if the click was on one of our 'a' tags. We did this by making our EntryPoint class implement the GWT Event.NativePreviewHandler interface as follows:
    public void onPreviewNativeEvent(Event.NativePreviewEvent event) {
        if (SC.isIE() && event.getTypeInt() == Event.ONCLICK) {
            NativeEvent nativeEvent = event.getNativeEvent();
            EventTarget target = nativeEvent.getEventTarget();
            if (Element.is(target)) {
                Element element = Element.as(target);
                if ("a".equalsIgnoreCase(element.getTagName())) {
                    // make sure it's not a hyperlink that GWT already
                    // handles
                    if (element.getPropertyString("__listener") == null) {
                        String url = element.getAttribute("href");
                        String historyToken = getHistoryToken(url);
                        if (historyToken != null) {
                            GWT.log("Forcing History.newItem(\"" +
                                historyToken + "\")...");
                            History.newItem(historyToken);
                            nativeEvent.preventDefault();
                        }
                    }
                }
            }
        }
    }

    private static String getHistoryToken(String url) {
        String token;
        if (url.startsWith("#")) {
            token = url.substring(1);
        } else if (url.startsWith("/#")) {
            token = url.substring(2);
        } else if (url.contains(Location.getHost()) && url.indexOf('#') > 0) {
            token = url.substring(url.indexOf('#') + 1);
        } else {
            token = null;
        }
        return token;
    }
We then add the native preview handler at app load time by adding the following line to our EntryPoint class:
Event.addNativePreviewHandler(this);
This solution is working great. However, we still might eventually go back and switch over to using GWT HyperLinks, rather than raw HTML, in places where it is feasible, such as FormItems, since it is generally better to use widgets rather than raw HTML to keep things object-oriented and leave the generation of HTML, CSS, and JavaScript to the framework.

Setting Up IntelliJ IDEA on Fedora

JetBrains does not provide rpm's for IDEA, so setting it up on Fedora requires a bit of extra work. Here are the steps that I do.

Unzip the Distribution
# cd /opt
# tar -xzvf /path/to/ideaIC-10.5.tar.gz

This will create the directory /opt/idea-IC-107.105.

Create Symbolic Links
# cd /opt
# ln -sf /opt/idea-IC-107.105 /opt/idea
# ln -s /opt/idea/bin/idea.sh /usr/local/bin/idea

I overwrite the /opt/idea symlink each time I install a new version of IDEA. Creating the /usr/local/bin/idea symlink effectively adds idea to the system PATH. You'll only need to create this one the very first time you install IDEA.

Set JDK Environment Variable

idea.sh checks the IDEA_JDK, JDK_HOME and JAVA_HOME environment variables, in that order of preference, to determine the JVM it will use to run IDEA. Make sure one of these points to a JDK 6 installation. I am currently using JRockit, but the Sun JDK or OpenJDK will also work.

Update idea.vmoptions

The projects I work on are usually quite large, and my box is pretty beefy, so I always pump up the JVM's heap size and permgen size.
# cd /opt/idea/bin
# mv idea.vmoptions idea.vmoptions.orig
# cp /path/to/my/idea.vmoptions .

For reference, here's my idea.vmoptions file, though you will probably not want to use it verbatim:
-Xms1500M
-Xmx3000M
-XX:MaxPermSize=500M

Create a GNOME .desktop File

This will add an application launcher to the GNOME Applications menu. As root, create a file named idea.desktop in /usr/share/applications with the following contents:
[Desktop Entry]
Encoding=UTF-8
Version=1.0
Name=IntelliJ IDEA
GenericName=Java IDE
Comment=IntelliJ IDEA is a code-centric IDE focused on developer productivity. The editor deeply understands your code and knows its way around the codebase, makes great suggestions right when you need them, and is always ready to help you shape your code.
Exec=idea
Icon=/opt/idea/bin/idea_CE128.png
Terminal=false
Type=Application
Categories=Development;IDE

If you wish to tweak this file at all, the syntax for .desktop files can be found here.

Tuesday, January 26, 2010

JD-GUI on 64-bit Fedora 12

I just setup JD-GUI, a Java decompiler, on my 64-bit Fedora 12 box. I went with JD-GUI, because, unlike JAD, it supports Java 5 and 6 class files and is actively maintained.

A 32-bit Linux binary can be downloaded from the JD-GUI homepage. The tar.gz file just contains a single binary executable. I installed it as follows:
tar -xzvf jd-gui-0.3.3.linux.i686.tar.gz 
sudo mv jd-gui /usr/local/bin
Since my box is 64-bit, I was missing a handful of 32-bit libraries on which JD-GUI depended. Fortunately, these were all available from the default Fedora yum repos and can be installed using the following command:
sudo yum install libcanberra-gtk2.i686 PackageKit-gtk-module.i686 gtk2-engines.i686
These are the packages for Fedora 12 or later. If you're on Fedora 11, suffix the package names with .i586, rather than .i686. For Fedora 10, use .i386 as the suffix.

If you're using GNOME as your desktop environment, you may also want to associate .class files with JD-GUI. To do so, open File Browser and find a .class file. Right-click on the class file and select Properties. Select the Open With tab, click the Add button, select "Use a custom command", enter "/usr/local/bin/jd-gui", and finally click the Add button. Now when you double-click on a .class file from the File Browser, it will open that file using JD-GUI.