Maven 3 and the versions dilemma

Like many companies NBIC uses Maven to build  Java projects and manage the dependencies of the projects. Especially in combination with IDEs like Netbeans that understand Maven projects you have a powerful tool to quickly get started with your project and keep your builds in check.

Recently we have started the migration to Maven 3, because some of our builds had been triggering an issue in Maven 2 where the metadata for the plugins lost all version information. However, since then we have seen warnings about missiong versions for the plugins on projects that used to compile without warning.

I started to investigate the problem, but so far haven’t found a satisfactionary solution.

The problem

If you have a fairly simple configuration you might not notice the problem. Consider the following small example. This will build fine without any warnings.

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>net.example</groupId>
    <artifactId>app</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>
    <name>Example App</name>
</project>

However, in many cases you might want to configure some of the compilation parameters. For example if you need to build your project for a specific (older) version of Java. Like in the following example:

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>net.example</groupId>
    <artifactId>app</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>
    <name>Example App</name>
    <build>
        <plugins>
            <plugin>
                <inherited>true</inherited>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

The small change introduced here to specify the target version of Java will give you the warnings below.

[WARNING] Some problems were encountered while building the effective model for net.example:app:pom:0.0.1-SNAPSHOT
[WARNING] 'build.plugins.plugin.version' for org.apache.maven.plugins:maven-compiler-plugin is missing. @ line 11, column 12
[WARNING] It is highly recommended to fix these problems because they threaten the stability of your build.
[WARNING] For this reason, future Maven versions might no longer support building such malformed projects.

So, Maven tells us that we should specify the version of the plugin, but what is the best approach? I have played with a couple of approaches, but so far I haven’t found a satisfactory solution.

Approach 1: hardcoded versions

The easy way out seems to be to hardcode the version of the plugin in your pom.xml. Adding the <version> tag to the plugin definition will suffice.

However, while it is not a problem if you just have a simple project, this solution soon becomes a hassle when you have to work with complex projects that consist of dozens of modules or when you have many projects that should all use the same version of the plugin.

There are a couple of approaches that can alleviate this issue.

Approach 2: using properties

Using properties makes it easier to maintain a consistent set of plugin versions, because you can refer to the version by property and only define the version once. It does require some discipline to maintain, because plugins introduced by IDEs like NetBeans will not have their version set by properties, and you have to change the pom.xml file to adjust.

Creating the properties however is fairly easy. With the <properties> tag you can introduce any property by creating a tag named after the property. Afterwards you can refer to it by the name you gave to the tag, like in the following example:

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>net.example</groupId>
    <artifactId>app</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>
    <name>Example App</name>
    <properties>
        <maven-compiler-plugin-version>2.3.2</maven-compiler-plugin-version>
    </properties>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${maven-compiler-plugin-version}</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

If your project has multiple modules, the modules can use the properties defined in the parent project. However, you have to take care that you always introduce the properties in the parent pom.xml.

Approach 3: using a company wide master pom

Using a company wide master pom is a variant on creating a modular project. Each project will have the company wide master pom as parent, and you can introduce the plugins in this master pom file. The main disadvantage is that it will introduce yet another dependency and changes in the master pom might trigger all your projects to be rebuild in your CI environment.

Automating version management

The versions plugin is a way to automate the management of versions. It takes the hard labour out of finding out about the latest versions of the plugins and updating the pom.xml. It works with hard-coded versions as well as parameterized versions using properties. It can be used both for the build dependencies as well as the plugin dependencies. It is however dangerous to just blindly update your versions, because you might upgrade to incompatible newer releases or stumble upon the issue that an illegal version of commons logging was pushed as shown below:

[INFO] Updated ${commons.logging.version} from 1.1.1 to 99.0-does-not-exist

Conclusions

There are several ways to remove the warning from Maven 3, however none of the offers the definitive solution to the problem of managing the versions in your maven project. Using properties in the parent pom.xml seems to give the best trade-off between the requirement of encoding your versions and management of your versions. The versions plugin seems to me to be a very dangerous plugin. It is a convenient tool to set the versions at the start of your project, but for updating a complex project it misses the required granularity in operations.

Posted in Software | Tagged , , , , | 1 Comment

Configuring Red Hat Enterprise Linux 5 or CentOS 5 for IPv6

With the last 5 /8 blocks of IP addresses being issued it is time to make your systems available through IPv6 if you haven’t done so yet. This short post shows how to configure a Centos or Red Hat Enterprise Linux (RHEL) system for IPv6.

Configuring your system consists of two distinct steps. First, you need to enable IPv6 on your network interface and second you need to configure your applications to bind to the right IPv6 addresses.

Before you begin

Like their IPv4 siblings the addresses in the IPv6 space are assigned to you. You cannot just make up your own IPv6 addresses and expect things to work. Check with your provider if they already support IPv6 and request an IPv6 subnet. Contrary to IPv4 you will not get a single IP address, but you will always get a subnet. Usually this will be a /64 subnet giving you the liberty to pick addresses within that space. If you have a significant number of addresses in use in your IPv4 space then it might be wise to consider the way you issue your IPv6 addresses. One way to do it could be to map the IPv4 address into the IPv6 address so you can easily see which addresses belong together.

Example network

In this document I use the official prefix for documentation purposes where-ever a network address is used. For IPv6 this is 2001:db8::/32, while for IPv4 I use the 192.0.2.0/24 network.

2001:db8:abc::/48 is my sample provider network with 2001:db8:abc::1/48 as it’s gateway. For our network I use 2001:db8:abc:1234::/64. I assume a pre-existing IPv4 network with the following addresses: 192.0.2.1/24 for the default gateway and 192.0.2.100/24 and 192.0.2.200/24 as two addresses assigned for us to use on the server.

The network

Network configuration for IPv6 is done through the same configuration files as the other networking configuration. The system-config-network-tui command does support IPv6 so you have to edit the files by hand.

First edit /etc/sysconfig/network and make sure that IPv6 networking is enabled by setting NETWORKING_IPV6 to yes:

NETWORKING=yes
NETWORKING_IPV6=yes
HOSTNAME=www.example.com
GATEWAY=192.0.2.1
IPV6_DEFAULTGW="2001:db8:abc::1/48"

Here we have also setup the default IPv6 gateway with IPV6_DEFAULTGW.

Next step is to configure the network interface. In our example we have already two pre-existing IPv4 addresses configured on the eth0 interface and we want to map them to into our reserved IPv6 subnet. The first address we have is 192.0.2.100, which will map to 2001:db8:abc:1234::192.0.2.100 or 2001:db8:abc:1234::c000:264, the second address we have is 192.0.2.200, which maps to 2001:db8:abc:1234::192.0.2.200 or 2001:db8:abc:1234::c000:2c8. If you want to calculate your own IPv6 addresses you can easily do so with the following rule:

  1. Take your prefix (e.g. 2001:db8:abc:1234::)
  2. Add the IPv4 address (e.g. 192.0.2.100) after the double colon
  3. The resulting address is your IPv6 address, which you can convert with ipv6calc to the format using only the IPv6 notation with colons. (e.g. ipv6calc 2001:db8:abc:1234::192.0.2.100)

So, to configure the network interface we will edit the file /etc/sysconfig/network-scripts/ifcfg-eth0 and add the IPv6 configuration:

DEVICE=eth0
BOOTPROTO=static
IPADDR=192.0.2.100
NETMASK=255.255.255.0
HWADDR=01:23:45:67:89:AB
ONBOOT=yes
IPV6INIT=yes
IPV6ADDR="2001:db8:abc:1234::c000:264/48"
IPV6ADDR_SECONDARIES="2001:db8:abc:1234::c000:2c8/48"

As you might have noticed instead of using the /etc/sysconfig/network-scripts/ifcfg-eth0:1 for the second address we can use the IPV6ADDR_SECONDARIES line to add as many secondary addresses to the interface as necessary.

With our basic networking ready we can restart the networking with the command service network restart or a reboot, but make sure that you have access to your server’s console in case you made a mistake and the network doesn’t come up again.

Once your network is up again you should be able to verify the configuration by pinging the gateway or an other IPv6 enabled host with the ping6 command.

Configuring services for IPv6

Many of the services will use IPv6 automatically if an IPv6 network is present at startup, some services require explicit configuration to enable IPv6. I will shortly mention those that I needed to configure on my own server.

Postfix

Postfix needs to be told to use IPv6 by adding inet_protocols = all to the /etc/postfix/main.cf, also if you have mynetwork_style = class or mynetwork_style = subnet configured you need to be aware that your entire IPv6 subnet will be considered part of the my network. If your server is not the relayhost or smarthost for other servers I would strongly suggest to keep the mynetwork_style = host or manually define the mynetwork.

Dovecot

To make Dovecot listen on IPv6 addresses it needs to have an explicit listen configuration added. To make it listen on all addresses add the line listen = *, [::].

Apache httpd

If your Apache httpd is configured with Listen *:80 and NameVirtualHost *:80 it will automatically listen on IPv6 addresses. However if you use IP based virtual hosts you will need to add the IPv6 IP addresses to the VirtualHost configurations. You will need to use the address within brackets to make a distinction between the colon used as separator between the sections in the address and the colon as separator between the address and port. You can use multiple addresses in a single VirtualHost configuration as in the following example:

<VirtualHost 192.0.2.100:443 [2001:db8:abc:1234::c000:264]:443>
  DocumentRoot /var/www/html
  ServerName www.example.com
  ServerAdmin webmaster@example.com
  …
</VirtualHost>

Securing our IPv6 network

So far we haven’t looked at securing the network. The principles here are very much the same as with IPv4. The methods available are basically the same. You can use IPv6 addresses in the same way as IPv4 addresses in /etc/hosts.deny and /etc/hosts.allow as shown in the following example:

ALL:  [2001:db8:abc:1234::]/64

NetFilter works pretty much the same for IPv6, but uses different tables. You use the command ip6tables instead of iptables to manipulate the IPv6 rules:

ip6tables -I INPUT -s 2001:db8:abc:1234::/64 -j ACCEPT

You use the command: service ip6tables start to start the firewall, and enable it at startup with: chkconfig ip6tables on.

N.B.: There is one caveat, it seems the 2.6.18 kernel modules do not support stateful inspection of IPv6 traffic.

N.B.: Be aware that IPv6 relies heavily on ICMPv6 for all kinds of traffic and route information, so it is not wise to drop this traffic.

The Apache httpd Allow and Deny options works with IPv6 as well, you specify the IPv6 address just as you would specify an IPv4 address like in the following example:

Order allow,deny
Allow from 192.0.2.100 2001:db8:abc:1234::c000:264

And you can use networks as well as in the following example:

Order allow,deny
Allow from 192.0.2.0/24 2001:db8:abc:1234::/64

Conclusions

Configuring IPv6 is not that hard, and gives you the benefit of having your own subnet with plenty of space for future growth. Support in Red Hat Enterprise Linux or CentOS 5 is pretty good, with only a small caveat with iptables. If your provider supports IPv6 there is no reason not to implement it at the moment. Even though providers in the western world may still have a decent supply of IPv4 addresses it is very clear that in the coming years there will be a major shift towards IPv6, because we now have really reached the end of the availability of IPv4 addresses.

 

Posted in Software | Tagged , , , , | 1 Comment

Setting up VNC desktop sharing

In his blog post Remote meeting participants? We use Skype and VNC Rob Hooft discusses how we came to use a combination of Skype and VNC for our meetings after evaluating a couple of conferencing options. In this post I would like to follow this up with a technical overview of what’s necessary to set up your own VNC based screen sharing.

The server side

On the server you need to have an desktop environment that can be shared through VNC. This can be the X Window system with a desktop like Gnome or KDE on Linux. You also want to have the common desktop tools like a web browser, office software and a PDF viewer installed to actually share presentations or documents.

To show your desktop you will need a VNC server to which everyone can connect. We experienced with TightVNC and vnc4server. We found vnc4server to be the most stable, both of them are readily available in the software repositories of the most common Linux distributions.

To make it easy for everyone to join the conference we use a small web-page that serves to distribute a Java VNC applet to the users. Because of applet security sand-boxing the web page must reside on the same server as the VNC server. So you will need to have a web server configured as well. The web page can be really simple as showed below:

<html>
<title>shared desktop</title>
<body>
<applet archive="TightVncViewer.jar"
 code="com.tightvnc.vncviewer.VncViewer"
 width="1024" height="768">
<param name="Port" value="5901">
<param name="Scaling Factor" value=100>
<param name="View only" value="Yes">
<param name="Share desktop" value="Yes">
<param name="Show controls" value="No">
</applet>
<br>
<a href="http://www.tightvnc.com/">TightVNC Web Site</a>
</body>
</html>

The page refers to the applet TightVncViewer.jar which can be found on the TightVNC website. You also need to pay attention to the applet parameters marked in red above, and verify that they match your configuration.

If you want to have an encrypted connection you can configure the VNC Viewer to use an SSH connection. We currently don’t use it, since we simply shut down the VNC server when it is not needed. Depending on your configuration you will need to open up the HTTP port (80/tcp) and either VNC port (590x/tcp) or SSH port (22/tcp) for connections from the internet. If your server is directly connected to the internet and uses the iptables firewall a line similar to this will usually suffice:

iptables -I INPUT -p tcp -m multiport --dports 80,5901 \
         -m state --state NEW \
         -m comment --comment 'Web and VNC for conference' \
         -j ACCEPT

To start the service you simply login with SSH and start the vncserver command. If you start vncserver for the first time you will be prompted to give a VNC password, this is the password you give to the participants in your conference to access the shared screen. If you later on want to change the password you can do so with the vncpasswd command.

After your conference is finished you can stop your vnc server with the vncserver -kill command.

The client side

On the client side not that much is needed. The watchers need a web browser with support for Java, the presenter will need an SSH connection to start up the VNC server (unless you decide to keep it always running) and a full VNC client to control the screen. Since you don’t have voice over the VNC connection we use it in combination with Skype to set up the conference call. You can use the Skype chat functionality to share link and the password to access the VNC shared screen.

Limitations

Even though it has been a pretty smooth ride so far, there are some limitations you have to consider if you decide to use VNC for a shared desktop.

  • The distinction between the presenter and the viewers is not implemented in the vnc4server, so it’s easy for someone to take over control if he knows the password. Connecting with a regular VNC client will give you full control, and the HTML code for the applet will expose everything one needs to know to connect, so obfuscation by changing the port won’t help a bit. TightVNC however, does make the distinction between a full control password and a view only password.
  • Sometimes the screen is lagging a bit, this means sharing movies or animations might be problematic
  • No sound, but we share voice through skype.
  • No support for iPad, iPhone or other devices that don’t support Java.
  • Clipboard support over VNC is not optimal.

Conclusions

If you have a server on which you can install a desktop environment, a web server and a VNC server you have a cheap conferencing solution in combination with Skype, which in our experience can compete with many commercial solutions.

Posted in Software | Tagged , , , | 1 Comment

OpenJDK on the Mac

Recently Apple Inc. surprised users with a small note in the latest Java 1.6 updating stating that Apple would deprecate the Apple JDK on Mac OS X. For a while users of the system were left in uncertainty about the feasability to keep using Java on Mac OS X. Even though Apple was not always as fast as one would like with providing security updates or new releases of Java, the fact that it shipped with the OS gave some comfort about its support.This week Apple and Oracle jointly announced the project to bring OpenJDK to the Mac. Though it brings some relief to the Mac users still many questions remain.

  1. When will we see the first results of this project?
  2. Will Apple and Oracle make it easy to install OpenJDK (through the new Mac Store)?
  3. Will this actually improve the speed of releasing new versions and security updates for the Mac version?
  4. Will the PowerPC based Macs be supported?
  5. What does it mean that a new graphical client will be developed?
  6. Will it integrate seemlessly with the Mac desktop?
  7. Will applications continue to use a system default Java install, or will applications start to ship with their own version, with all the risks of duplication and outdated versions?
  8. Will there be a robust update procedure that will promptly notify the administrator about new versions, while not being obtrusive or a system hog?

The answer to most of these questions lies firmly with Apple and Oracle. We can hope that Apple’s usual attention to providing a good user experience will prevail and give us a better future for Java on the Mac, but it is upon us users to ask these critical questions and make sure they will be addressed.

If it all works out it will be for the better and make Mac OS X a little bit more open, which is not a bad thing with all the movements Apple has made towards closed systems and more control in the last years.

Posted in Software | Tagged , , | Leave a comment

Hacking the Safari search engine

How to use Apache to change the search engine used by the Safari search box.

Introduction

On my Mac I prefer to use the Safari web browser, because it is fast and well integrated into the system. However there is one thing I don’t like… I don’t have any choice to which search engine I use with the search field in the browser.
There are several existing hacks to change the search engine, but either they change the Safari binary, which does not play well with codesigning, or they work with plugins that use undocumented and unsupported hooks in the browser or system.
I wanted to do it in a way that does not break when I update Safari.

The fix

When looking at the problem I quickly realised that it is very easy to recognize the requests that Safari makes, because the query string contains the parameter client=safari. So the idea was born to rewrite the request so the searches are redirected to lxquick.com, while everything else still goes to Google. With Apache 2.2 every Mac has the tool to make this happen.

Implementation

First make sure that Apache is running by checking ‘Webserver’ in the ‘Sharing’ System Preference.

Next you need to make a couple of files and place all of them in the /etc/apache2/other directory. To write in this directory you need to have admin privileges, since we need to do several things on the command line as root we start with a sudo -s to get a root shell.

First, create /etc/apache2/other/search.conf. I will explain some of the code here in the following section.

<VirtualHost *:80>
  ServerName www.google.com

  RewriteEngine On
  RewriteCond %{QUERY_STRING} client=safari
  RewriteCond %{QUERY_STRING} q=([^&]*)
  RewriteRule ^/search http://ixquick.com/do/metasearch.pl?query=%1

  ProxyPass / http://www.l.google.com/
  ProxyPassReverse / http://www.l.google.com/
  ProxyPreserveHost On
</VirtualHost>

Listen *:443

<VirtualHost *:443>
  ServerName www.google.com
  ProxyPass / https://www.l.google.com/
  ProxyPassReverse / https://www.l.google.com/
  ProxyPreserveHost On
  SSLEngine On
  SSLProxyEngine On
  SSLCertificateFile /etc/apache2/other/server.crt
  SSLCertificateKeyFile /etc/apache2/other/server.key
</VirtualHost>

Second, create a self signed certificate for www.google.com.

openssl genrsa 1024 > /etc/apache2/other/server.key
openssl req -new -key /etc/apache2/other/server.key -x509 -days 1000000 -out /etc/apache2/other/server.crt

OpenSSL will ask you a couple of questions for the second command. Most of these questions are not really of importance, since we are creating a self signed certificate. Only you do want the Common Name attribute to be www.google.com, otherwise the browser will always ask you for permission to use the certificate.

Now the Apache configuration is ready. You can have Apache test your configuration with the following command:

apachectl configtest

If everything is okay you can restart Apache with the command:

apachectl restart

Now you only have to fool the system so it will redirect requests for http://www.google.com to your apache install. Luckily this is really easy. We just have to edit the file /etc/hosts and add www.google.com at the end of the line starting with 127.0.0.1, so it should read:

##
# Host Database
#
# localhost is used to configure the loopback interface
# when the system is booting.  Do not change this entry.
##
127.0.0.1	localhost www.google.com
255.255.255.255	broadcasthost
::1             localhost
fe80::1%lo0	localhost

Finish everything by restarting Safari and browse to https://www.google.com/. You will get a certificate warning, because we use a self signed certificate. Select to trust the certificate permanently and you’re good to go.

The magic

There are three pieces of magic at work here.

  1. The hosts files allows us to override the DNS for www.google.com
  2. The proxy module in Apache allows us to act as a proxy for www.google.com
  3. The rewrite engine of Apache makes it possible to change just the requests from the Safari search box and send them to lxquick.com

Point 2 & 3 need some explanation.

proxying for www.google.com

The following three lines in the configuration are at the heart of our tip.

  ProxyPass / http://www.l.google.com/
  ProxyPassReverse / http://www.l.google.com/
  ProxyPreserveHost On

ProxyPass and ProxyPassReverse make sure that the requests are sent to Google, and the last makes sure that we tell the Google servers that we want pages for www.google.com. Google makes it very easy for us, because www.google.com is a CNAME for www.l.google.com. This allows us to refer to exactly the same servers with a different name.

Rewriting the requests

The rewrite engine allows us to rewrite a request only if it meets specific conditions. In our case the browser makes a request for http://www.google.com/search?client=safari&rls=en&q=bla&ie=UTF-8&oe=UTF-8. In the code below the conditions are specified with the RewriteCond and what we want to do is specified in the RewriteRule.

 RewriteEngine On
  RewriteCond %{QUERY_STRING} client=safari
  RewriteCond %{QUERY_STRING} q=([^&]*)
  RewriteRule ^/search http://ixquick.com/do/metasearch.pl?query=%1

We use two conditions to work our magic. The first is that the URL must match client=safari in the query string. The second one is that we must have a search term specified with q=. In this second condition we have some additional magic. The parenthesis tell the rewrite engine that we want to refer back to the result of the expression within the rewrite rule. Between the parenthesis we have a rule that says that we want take all of the query string till the next occurrence of the & or the end of the line.
In the Rewrite rule we tell that we want to rewrite request that start with /search and meet the two conditions above. Of course we also need to specify how we want to rewrite them. Here we put the URL that lxquick expects for a search request. The %1 here is special, because it refers back to the data that matched with our expression within the parenthesis in our second rewrite condition.

Posted in Howto, Mac | Tagged , , , | Leave a comment