February 8, 2014

SVNKit - Check if the given file has the executable flag set

Earlier today I had to code up with code checking if the given SVN url points to a file that has the executable flag set. As Google was not able to find any complete solution using the SVNkit library, here it is:
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNNodeKind;
import org.tmatesoft.svn.core.SVNProperties;
import org.tmatesoft.svn.core.SVNProperty;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.auth.BasicAuthenticationManager;
import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory;
import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil;
import org.tmatesoft.svn.core.internal.util.SVNURLUtil;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.io.SVNRepositoryFactory;

public class SvnClient {
  private String username;
  private String password;
  
  public SvnClient(String username, String password) {
    super();
    this.username = username;
    this.password = password;
  }

  protected SVNRepository connectToRepo(String url) {
    // For using over http:// and https://
    DAVRepositoryFactory.setup();
        
    try {
      final SVNURL svnUrl = SVNURL.parseURIEncoded(url);

      final SVNRepository repository = SVNRepositoryFactory
        .create(svnUrl);
      
      final ISVNAuthenticationManager authManager = 
        new BasicAuthenticationManager(username, password);
      repository.setAuthenticationManager(authManager);
          
      repository.testConnection();
          
      return repository;
    } catch (SVNException e) {
      throw new RuntimeException("Error while connecting to SVN, url "
        + url, e); 
    }        
  }

  public boolean hasExecutableFlagSet(String url, long revision) {
    final SVNRepository repository = connectToRepo(url);
    try {     
      SVNURL repositoryRoot = repository.getRepositoryRoot(true);
      final String fileRelativeURL = "/" + 
        SVNURLUtil.getRelativeURL(repositoryRoot, 
          SVNURL.parseURIEncoded(url), false);
      
      final SVNProperties properties = new SVNProperties();
            
      repository.getFile(fileRelativeURL, revision, properties, null);

      String value = properties.getStringValue(
        SVNProperty.EXECUTABLE);
      
      return value != null;
    } catch(SVNException e) {
      throw new RuntimeException("Error while checking if object "
        + "has the executable flag set, "
        + "url " + url + ", revision " + revision, e);
    } finally {
      repository.closeSession();
    }
  }
  
}

January 12, 2014

Tricky Java job interview questions #1 - discarded exceptions

In May last year I have joined Stackoverflow and started following Java questions. After a few months of actively participating in Stackoverflow, answering questions and learning from others' answers I must say that Stackoverflow is a great source of knowledge. Yes, there are a lot of very simple questions, but among them there are also challenges.

During the last few months I have seen numerous very interesting, and tricky, questions, questions that might be used on Java job interviews. Without further ado, let us start with question #1: What will be the result of executing the following code:

try {
    try {
        System.out.print("1");
        throw new Exception("a");
    } catch (Exception e) {
        System.out.print("2");
        throw new Exception("b");
    } finally {
        System.out.print("3");
        throw new Exception("c");
    }
} catch (Exception e) {
    System.out.print(e.getMessage());
}

Answer: 123c

Explanation: When a finally block throws an Exception (Exception("c")) then the exception thrown in the try block (Exception("b")) is discarded
From the Java Language Specification 14.20.2.:
If execution of the try block completes abruptly for any other reason R, then the finally block is executed, and then there is a choice:
  • If the finally block completes normally, then the try statement completes abruptly for reason R.
  • If the finally block completes abruptly for reason S, then the try statement completes abruptly for reason S (and reason R is discarded).


Inspired by this Stackoverflow question.

December 20, 2013

JAXB automatically will NOT marshal fields with non-public getter/setter pairs

Recently I have been investigating why JAXB does not marshal one of the classes in the application I was working on. This class had its setters marked as protected, while all the other classes had public setters. As it has turned out this discrepancy was responsible for the issue.

JAXB by default marshals only fields that have a corresponding setter/getter pair marked as public.

So when you want to marshal such class:
@XmlRootElement
public class User implements Serializable {
    private static final long serialVersionUID = 1L;

    private Integer id;
    private String name;
 
    public Integer getId() {
        return id;
    }
    protected void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    protected void setName(String name) {
        this.name = name;
    } 
}
you have to append the following annotation:
@XmlAccessorType(XmlAccessType.FIELD)

May 17, 2013

Checked or unchecked exception in Java - decide on the method responsible for performing the check approach

While reading Martin Fowler's book "Refactoring" I came across below paragraph suggesting when choose a checked and when an unchecked exception.

class Account... 
  int withdraw(int amount) {
      if (amount > _balance) return -1;
      else { _balance -= amount; return 0; 
  } 
  private int _balance;
}
To change this code to use an exception I first need to decide whether to use a checked or unchecked exception. The decision hinges on whether it is the responsibility of the caller to test the balance before withdrawing or whether it is the responsibility of the withdraw routine to make the check. If testing the balance is the caller's responsibility, it is a programming error to call withdraw with an amount greater than the balance. Because it is a programming error—that is, a bug—I should use an unchecked exception. If testing the balance is the withdraw routine's responsibility, I must declare the exception in the interface. That way I signal the caller to expect the exception and to take appropriate measures.

I think this is a great guideline, helping in this very, very, very frequent dilemma in the Java world.

I have entitled this approach decide on the method responsible for performing the check approach, it can be summarized as:

  • If it is the caller method should perform a check prior calling the called method (e.g. making sure the arguments are not not null) then if such check has not been done it is clearly a programming error and then the called method should thrown an unchecked exception.
  • It is the called method responsibility to make the check, because only this method can know how to perform such check then the exception thrown from the called method should be checked.

I have done some research checking how the above approach to the checked vs unchecked exception dilemma is applied in the Java world.

  1. java.io.File throws an unchecked NullPointerException when null is passed as the filename to the constructor
  2. public File(String pathname) {
      if (pathname == null) {
        throw new NullPointerException();
      }
      this.path = fs.normalize(pathname);
      this.prefixLength = fs.prefixLength(this.path);
    }
    

    It is the responsibility of the caller to make sure the mandatory arguments provided to the constructor are not nulls.

  3. java.io.File throws java.lang.IllegalArgumentException when an incorrect URL is passed to the constructor
  4. public File(URI uri) {
      if (!uri.isAbsolute())
        throw new IllegalArgumentException("URI is not absolute");
      if (uri.isOpaque())
        throw new IllegalArgumentException("URI is not hierarchical");
      String scheme = uri.getScheme();
      if ((scheme == null) || !scheme.equalsIgnoreCase("file"))
        throw new IllegalArgumentException("URI scheme is not \"file\"");
      if (uri.getAuthority() != null)
        throw new IllegalArgumentException("URI has an authority component");
      if (uri.getFragment() != null)
        throw new IllegalArgumentException("URI has a fragment component");
      if (uri.getQuery() != null)
        throw new IllegalArgumentException("URI has a query component");
      String p = uri.getPath();
      if (p.equals(""))
        throw new IllegalArgumentException("URI path component is empty");
      /// ...
    }
    

    Same story here, it is the caller who is responsible for making sure the provided arguments are correct.

  5. java.util.zip.InflaterInputStream throws a checked java.util.zip.DataFormatException when read() encounters a problem reading the ZIP file
  6. public int read(byte[] b, int off, int len) throws IOException {
      try {
        // ...
      } catch (DataFormatException e) {
        String s = e.getMessage();
        throw new ZipException(s != null ? s : "Invalid ZLIB data format");
      }
    }
    

    It is the responsibility of this (called) method to not only read a zip file but also to validate if the zip file is correct. If it is not valid, what is possible, the calling method should be notified about that.

  7. A checked java.rmi.AlreadyBoundException is thrown when a name provided to java.rmi.Naming.bind() is already bound
  8. public static void bind(String name, Remote obj) throws AlreadyBoundException // ...
    

    The responsibility of checking if the given name is already bound or not might be pushed onto the calling method as there is a method to check if the provided name is bound or not (Naming.lookup()). However it is possible that the name that has been checked to be available has been bound by another process/thread between the call to the lookup and bind method. Therefore a situation when this exception is thrown seems to be perfectly natural and should not be treated as a development bug on the caller side.

  9. A programming error of calling operations on a closed stream results does not result in an unchecked exception but in a checked java.io.IOException
  10. I is it important to keep in mind that this approach is only a guideline, which means there are cases when it is not followed, even in the JDK source code.

    Below code snippet from StringReader:
    public int read() throws IOException {
      synchronized (lock) {
        ensureOpen();
        if (next >= length)
          return -1;
        return str.charAt(next++);
      }
    }
    
    private void ensureOpen() throws IOException {
      if (str == null)
        throw new IOException("Stream closed");
    }
    

    Causes below code to throw a checked IOException:

    StringReader reader = new StringReader("aa");
    
    reader.read();  
    reader.close();  
    reader.read();
    

    While it is clear that is the programmer's responsiblity to make sure that he is not calling any operations on an already closed stream.

    Exactly the same exception is also thrown in the following IO classes:
    • BufferedInputStream
    • BufferedReader
    • BufferedWriter
    • CharArrayReader
    • PrintStream
    • PrintWriter

May 3, 2013

Why I love MacOS - reason #1 - renice

I have been reading a PDF file and had a movie played in the background from a VOD service (plus of course a dozen of other applications that I never quit Skype, Chrome, iTerm, numerous services etc.). Every single time I was scrolling down the PDF file the movie hanged for a half a second. As you can imagine this was extremely annoying.

So I have increased the VOD process priority by changing its nice value and after that was able to continue doing these two tasks smoothly.

This is what I did

  • found the PID of the process playing VOD with "top -o cpu"
  • invoked "sudo renice -15 -p PID"

May 2, 2013

Bash script to get a diff with all the changes from the provided SVN branch

Despite there are numerous user friendly and feature-rich tools for doing code reviews, Crucible being the first one that comes to my mind, when I have to focus solely on the changes I personally prefer to resort to old-school vim with just syntax highlighting.

If you have the same preference, below is a short bash script that might be useful to you, given an SVN branch it will output all the changes from this branch.


#!/bin/bash
test $# -ne 1 && echo "Usage: $0 SVN_URL" && exit 1

svn="$1"
log=`mktemp svn_log.XXXXX`

svn log --stop-on-copy "$svn" > $log
first="`grep '^r[0-9]* | .* | .* |' $log | cut -c2- | cut -d\  -f1 | head -1`"
last="`grep '^r[0-9]* | .* | .* |' $log | cut -c2- | cut -d\  -f1 | tail -1`"

rm $log

svn diff -x "-w --ignore-eol-style" -r "${first}:${last}" $svn

So if you run this script against e.g. https://svn.apache.org/repos/asf/wicket/branches/wicket-1.5.0 you will get:

Index: wicket-guice/pom.xml
===================================================================
--- wicket-guice/pom.xml (revision 1164579)
+++ wicket-guice/pom.xml (revision 1164571)
@@ -23,7 +23,7 @@
  <parent>
   <groupId>org.apache.wicket</groupId>
   <artifactId>wicket-parent</artifactId>
-  <version>1.5.0</version>
+  <version>1.5-RC7</version>
   <relativePath>../pom.xml</relativePath>
  </parent>

Index: wicket-datetime/pom.xml
===================================================================
--- wicket-datetime/pom.xml (revision 1164579)
+++ wicket-datetime/pom.xml (revision 1164571)
@@ -21,7 +21,7 @@
...

May 1, 2013

Use Chrome/Firefox search engine functionality to directly jump into a specific issue from your tracking system

If you, like myself, very frequently have to jump right into a specific issue from your tracking system (JIRA, Redmine, Bitbucket, Trac, etc.) and find you it annoying having to use the search functionality or manually modify the URL below is a small productivity hint that might like.

Chrome (and Firefox) is equipped with a handy feature enabling to search using the defined search engines right from the browser address bar. You just need to type the search engine name, press tab and enter your query string. This feature can also be used to search for a specific issue in your tracking system.

To configure that in Chrome go to Settings / Basics / Search and enter:

  • your search engine name
  • keyboard shortcut
  • URL with %s which will be replaced with whatever you type in the address bar

For example for JIRA this might look like:

  • issue
  • i
  • http://your-jira.com/browse/%s

Now type "i" in the address bar, press tab, enter an issue id, hit enter… and you are inside the issue.