Efficiently searching the Java API

      No Comments on Efficiently searching the Java API

Since Sun’s API search is a real pain in the arse and even DocWeb doesn’t allow you to quickly search the Java API, this firefox plugin is a substantial improvement: https://addons.mozilla.org/en-US/firefox/addon/60675/

It basically redirects the search query to Google’s “I’m Feeling Lucky” feature to search Java’s API for the class information.

Together with Second Search querying the Java API is now lightning fast: https://addons.mozilla.org/en-US/firefox/addon/4096/

Implementing equals() the right way

      No Comments on Implementing equals() the right way

At first sight, implementing equals() doesn’t seem fairly hard. Unfortunately, it turns out that writing a correct equality method is surprisingly difficult:

http://java.sun.com/javase/6/docs/api/java/lang/Object.html

The equals method implements an equivalence relation on non-null object references:

  • It is reflexive: for any non-null reference value x, x.equals(x) should return true.
  • It is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.
  • It is transitive: for any non-null reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true.
  • It is consistent: for any non-null reference values x and y, multiple invocations of x.equals(y) consistently return true or consistently return false, provided no information used in equals comparisons on the objects is modified.
  • For any non-null reference value x, x.equals(null) should return false.

In fact, after studying a large body of Java code, the authors of a 2007 paper concluded that almost all implementations of equals methods are faulty.1

There are quite a lot of HowTos available on the web. One of the best might be the article “How to Write an Equality Method in Java” by Martin Odersky, Lex Spoon, and Bill Venners.

So instead of repeating all the pitfalls you have to avoid, I’ll give you a sample implementation2 of the equals()-method that follows the general contract using the example of an imaginary class Point:

public boolean equals (final Object obj) {
    if (this == obj) {
      return true;
    }
    if (obj == null) {
      return false;
    }
    if (this.getClass() != obj.getClass()) {
      return false;
    }
    final Point other = (Point) obj;
    if (this.x != other.x) {
      return false;
    }
    if (this.y != other.y) {
      return false;
    }
    return true;
  }

Be careful: Whenever you overwrite equals() it is generally necessary to override the hashCode()-method, too!

If you want to learn more about this topic, I suggest, you have a look at Joshua Bloch’s Effective Java Second Edition. Addison-Wesley, 2008.

[1] Vaziri, Mandana, Frank Tip, Stephen Fink, and Julian Dolby. “Declarative Object Identity Using Relation Types.” In Proc. ECOOP 2007, pages 54–78. 2007.
[2] http://www.artima.com/forums/flat.jsp?forum=226&thread=259279&start=30&msRange=15

Using a HashSet in a thread-safe manner

      4 Comments on Using a HashSet in a thread-safe manner

Thread safety is a very hot topic for Java programmers right now. But I’ve seen quite a few folks using the rather complex collections from java.util.concurrent when they actually needed just a thread-safe implementation of a Set.

Of course, the HashSet implementation is non-thread-safe:

http://java.sun.com/javase/6/docs/api/java/util/HashSet.html

Note that this implementation is not synchronized. If multiple threads access a hash set concurrently, and at least one of the threads modifies the set, it must be synchronized externally. This is typically accomplished by synchronizing on some object that naturally encapsulates the set. If no such object exists, the set should be “wrapped” using the Collections.synchronizedSet method. This is best done at creation time, to prevent accidental unsynchronized access to the set:

So getting a thread-safe representation of the HashSet class is pretty easy:

   Set s = Collections.synchronizedSet(new HashSet(...));

This returns a synchronized set backed by the specified set. But be careful: In order to guarantee serial access, it is critical that all access to the backing set is accomplished through the returned set.

A further pitfall is the use of the class’s iterator

Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.

So it is imperative that you manually synchronize on the returned set when iterating over it:

  Set s = Collections.synchronizedSet(new HashSet());
      ...
  synchronized(s) {
      Iterator i = s.iterator(); // Must be in the synchronized block
      while (i.hasNext())
          foo(i.next());
  }
 

Failure to follow this advice may result in non-deterministic behavior.

Inside adsense’s show_ads.js

      2 Comments on Inside adsense’s show_ads.js

For those of you, who want to understand what goes on inside google adsense’s show_ads.js, here is the complete source code:

google_ad_url = '';
google_random = (new Date()).getTime();
google_org_error_handler = window.onerror;

function quoted(str) {
  return (str != null) ? '"' + str + '"' : '""';
}

function google_encodeURIComponent(str) {
  if (typeof(encodeURIComponent) == 'function') {
    return encodeURIComponent(str);
  } else {
    return escape(str);
  }
}

function google_write_tracker(tracker_event) {
  var img_url = window.google_ad_url.replace(/pagead\/ads/, 'pagead/imp.gif');
  var img_src = img_url + '&event=' + tracker_event;
  var img_tag = '<i' + 'mg height="1" width="1" border="0" ' +
                'src=' + quoted(img_src) +
                ' />';
  document.write(img_tag);
}

function google_append_url(param, value) {
  if (value) {
    window.google_ad_url += '&' + param + '=' + value;
  }
}

function google_append_url_esc(param, value) {
  if (value) {
    google_append_url(param, google_encodeURIComponent(value));
  }
}

function google_append_color(param, value) {
  if (value && typeof(value) == 'object') {
    value = value[window.google_random % value.length];
  }
  google_append_url('color_' + param, value);
}

function google_show_ad() {
  var w = window;
  w.onerror = w.google_org_error_handler;

  if (w.google_num_ad_slots) {
    w.google_num_ad_slots = w.google_num_ad_slots + 1;
  } else {
    w.google_num_ad_slots = 1;
  }

  if (w.google_num_ad_slots > 3) {
    return;
  }

  w.google_ad_url = 'http://pagead2.googlesyndication.com/pagead/ads?';
  w.google_ad_client = w.google_ad_client.toLowerCase();
  if (w.google_ad_client.substring(0,3) != 'ca-') {
     w.google_ad_client = 'ca-' + w.google_ad_client;
  }
  w.google_ad_url += 'client=' + escape(w.google_ad_client) +
                     '&random=' + w.google_random;

  google_append_url('hl', w.google_language);
  if (w.google_country) {
    google_append_url('gl', w.google_country);
  } else {
    google_append_url('gl', w.google_gl);
  }
  google_append_url('gr', w.google_region);
  google_append_url_esc('gcs', w.google_city);
  google_append_url_esc('hints', w.google_hints);
  google_append_url('adsafe', w.google_safe);
  google_append_url('oe', w.google_encoding);
  google_append_url('lmt', w.google_last_modified_time);
  google_append_url_esc('alternate_ad_url', w.google_alternate_ad_url);
  google_append_url('alt_color', w.google_alternate_color);

  if (w.google_skip) {
    google_append_url("skip", w.google_skip);
  } else if (w.google_prev_ad_formats) {
    google_append_url_esc('prev_fmts', w.google_prev_ad_formats.toLowerCase());
  }

  if (w.google_ad_format) {
    google_append_url_esc('format', w.google_ad_format.toLowerCase());
    if (w.google_prev_ad_formats) {
      w.google_prev_ad_formats = w.google_prev_ad_formats + ',' + w.google_ad_format;
    } else {
      w.google_prev_ad_formats = w.google_ad_format;
    }
  }

  google_append_url('num_ads', w.google_max_num_ads);
  google_append_url('output', w.google_ad_output);
  google_append_url('adtest', w.google_adtest);
  if (w.google_ad_channel) {
    google_append_url_esc('channel', w.google_ad_channel.toLowerCase());
  }
  google_append_url_esc('url', w.google_page_url);
  google_append_color('bg', w.google_color_bg);
  google_append_color('text', w.google_color_text);
  google_append_color('link', w.google_color_link);
  google_append_color('url', w.google_color_url);
  google_append_color('border', w.google_color_border);
  google_append_color('line', w.google_color_line);
  google_append_url('kw_type', w.google_kw_type);
  google_append_url_esc('kw', w.google_kw);
  google_append_url_esc('contents', w.google_contents);
  google_append_url('num_radlinks', w.google_num_radlinks);
  google_append_url('max_radlink_len', w.google_max_radlink_len);
  google_append_url('rl_filtering', w.google_rl_filtering);
  google_append_url('ad_type', w.google_ad_type);
  google_append_url('image_size', w.google_image_size);
  google_append_url('feedback_link', w.google_feedback);

  w.google_ad_url = w.google_ad_url.substring(0, 1000);
  w.google_ad_url = w.google_ad_url.replace(/%\w?$/, '');

  if (google_ad_output == 'js' && w.google_ad_request_done) {
    document.write('<scr' + 'ipt language="JavaScript1.1"' +
                   ' src=' + quoted(google_ad_url) +
                   '></scr' + 'ipt>');
  } else if (google_ad_output == 'html') {
    if (w.name == 'google_ads_frame') {
      google_write_tracker('reboundredirect');
    } else {
      document.write('<ifr' + 'ame' +
                     ' name="google_ads_frame"' +
                     ' width=' + quoted(w.google_ad_width) +
                     ' height=' + quoted(w.google_ad_height) +
                     ' frameborder=' + quoted(w.google_ad_frameborder) +
                     ' src=' + quoted(w.google_ad_url) +
                     ' marginwidth="0"' +
                     ' marginheight="0"' +
                     ' vspace="0"' +
                     ' hspace="0"' +
                     ' allowtransparency="true"' +
                     ' scrolling="no">');
      google_write_tracker('noiframe');
      document.write('</ifr' + 'ame>');
    }
  }

  w.google_ad_frameborder = null;
  w.google_ad_format = null;
  w.google_page_url = null;
  w.google_language = null;
  w.google_gl = null;
  w.google_country = null;
  w.google_region = null;
  w.google_city = null;
  w.google_hints = null;
  w.google_safe = null;
  w.google_encoding = null;
  w.google_ad_output = null;
  w.google_max_num_ads = null;
  w.google_ad_channel = null;
  w.google_contents = null;
  w.google_alternate_ad_url = null;
  w.google_alternate_color = null;
  w.google_color_bg = null;
  w.google_color_text = null;
  w.google_color_link = null;
  w.google_color_url = null;
  w.google_color_border = null;
  w.google_color_line = null;
  w.google_adtest = null;
  w.google_kw_type = null;
  w.google_kw = null;
  w.google_num_radlinks = null;
  w.google_max_radlink_len = null;
  w.google_rl_filtering = null;
  w.google_ad_type = null;
  w.google_image_size = null;
  w.google_feedback = null;
  w.google_skip = null;
}

function google_error_handler(message, url, line) {
  google_show_ad();
  return true;
}

window.onerror = google_error_handler;

if (window.google_ad_frameborder == null) {
  google_ad_frameborder = 0;
}

if (window.google_ad_output == null) {
  google_ad_output = 'html';
}

if (window.google_ad_format == null && window.google_ad_output == 'html') {
  google_ad_format = google_ad_width + 'x' + google_ad_height;
}

if (window.google_page_url == null) {
  google_page_url = document.referrer;
  if (window.top.location == document.location) {
    google_page_url = document.location;
    google_last_modified_time = Date.parse(document.lastModified) / 1000;
  }
}
google_show_ad();

Found on http://www.koders.com.

PulseAudio and lirc [Update]

      No Comments on PulseAudio and lirc [Update]

Changing the system volume with a lirc enabled remote can be a pain in the arse if you don’t know what to look for. If you do, it’s quite simple:

There is a package called ‘pulseaudio-module-lirc’ (PulseAudio’s Wiki for module-lirc) that contains the volume control module for the PulseAudio sound server.

Install the package via yum

# yum install pulseaudio-module-lirc

and enable it

# echo "load-module module-lirc" >> /etc/pulse/default.pa

Here is a sample ~/.lircrc entry configured to forward signals to PulseAudio. Note that you may have to change the remote name and button names to match those in you /etc/lirc/lircd.conf.

begin
   remote = [your remote name]
   prog = pulseaudio
   config = volume-down
   button = [your vol_down button name]
   repeat = 0
end

begin
   remote =  [your remote name]
   prog = pulseaudio
   config = volume-up
   button = [your vol_up button name]
   repeat = 0
end

begin
   remote =  [your remote name]
   prog = pulseaudio
   config = mute-toggle
   button = [your mute button name]
end

Available configs include: volume-up, volume-down, mute, mute-toggle and reset.

Eventually, you have to reload PulseAudio:

# killall pulseaudio && pulseaudio -D

Update:

If you happen to have multiple PulseAudio sinks, you may want to modify /etc/pulse/default.pa like this

[...]
load-module module-lirc sink=[your sink name]
[...]

where you can get the sink name from PulseAudio manager ‘paman’ (flip to the ‘devices’ tab, and copy the name of the sink that you want the lirc module to control).

Java plugin for Firefox 3.6

      1 Comment on Java plugin for Firefox 3.6

Since Mozilla dropped support on OJI (Open Java Virtual Machine Integration), the classic java plugin file javaplugin-oji.so doen’t work anymore for Firefox versions >3.6. Starting in Firefox 3.6, Mozilla will only support the standard NPAPI and NPRuntime interfaces.

However, a ‘Next-Generation Java plugin’ (that’s what Sun calls it) is available in Java version 6 update 10 or newer and supports the NPAPI and NPRuntime interfaces.

Installation is quite simple. Remove the symbolic links to libjavaplugin_oji.so from the Firefox plugins directory and replace it with to libnpjp2.so:

cd ~/.mozilla/plugins/
rm -f libjavaplugin_oji.so
ln -s <JRE>/lib/i386/libnpjp2.so . 

where <JRE> is the path to your Java runtime environment.

Resources:
http://java.sun.com/javase/6/webnotes/install/jre/manual-plugin-install-linux.html

Netboot CentOS using Attansic L1 Gigabit Ethernet

To update the initrd.img to load additional drivers early in the boot process, normally you would simply run /sbin/mkinitrd and let the script do the work. But what if the initrd.img used during the installation of CentOS lacks an important driver? Maybe you want to netboot CentOS, but the initial ramdisk CentOS provides doesn’t have the right modules for you NIC.

This article gives an example, how to modify the initrd.img to include the drivers for the Attansic L1 Gigabit Ethernet Adapter by hand. (If you just want to know, how to get CentOS working with the L1 without caring about netboot etc., have a look at CentOS and Attansic L1 Gigabit Ethernet)

Continue reading

Extract single file from tar archive

      No Comments on Extract single file from tar archive

Sometimes, extracting a whole tar archive can be a waste of time (and temporarily disk space).

To extract just a single file, you can use

tar -x file -zf archive.tar.gz -C /tmp/

This extracts the file file to /tmp/

Of course, most of the time the relative path to the file is not as simple as in the example above:

tar -x path/to/file -zf archive.tar.gz -C /tmp/

This creates the file /tmp/path/to/file.

To avoid the creation of the file’s relative path (or parts of it) in the target directory, use the switch --strip-components

tar -x path/to/file -zf archive.tar.gz -C /tmp/ --strip-components=2

This creates the file /tmp/file

And finally, you can use stdout redirection to achieve the same result

tar -x path/to/file -zf archive.tar.gz -O >/tmp/file

or even shorter

tar xfz archive.tar.gz path/to/file -O >/tmp/file

WordPress myStat plugin breaks rss feed

      1 Comment on WordPress myStat plugin breaks rss feed

I recently installed myStat to keep track of this blog’s rapidly increasing number of readers. Unfortunately, the plugin break the rss feed. The problem is the plugin’s myStat_footer() function, which does not check if the page is a feed before deciding to insert the myStat footer image into the page code.

To fix myStat v2.6, locate line 475 in mystat.php and change the myStat_footer() function

function myStat_footer() {
    global $cmn;
    if($cmn->getParam("myStat_debug")==1){$cmn->setDebug('FOOTER LOAD');};
    echo "<img style=(...);
}

like this

function myStat_footer() {
    global $cmn;
    if($cmn->getParam("myStat_debug")==1){$cmn->setDebug('FOOTER LOAD');};
    if (!is_feed()) {
        echo "<img style=(...);
    }
}

Resources:
http://wordpress.org/support/topic/325426