Friday, July 27, 2012

Java 7, one year later

Java 7, one year later

Java 7 got released on the 28'th of July 2011
The world wide launch party was on the 7'th of July at the JUG with Alexis Moussine-Pouchkine: http://2011.geecon.org/speakerdetails/12

I had the privilege of presenting at the Jozi JUG on the 29'th of August

JRebel claims the adoption is now at 23%
Jelastic claimed 18% in the same article.

Within Jelastic's cloud service: Java 7 is at a massive 73% vs Java 6 at 27%
graph
(Thanks Judah)

Here is the git location of the source code I demoed way back.

git clone https://bitbucket.org/rjdkolb/java7jozijug.git
 
Or on the web : https://bitbucket.org/rjdkolb/java7jozijug/src 


Wednesday, July 25, 2012

Improving the performance of a Vaadin OpenLayers Map

The problem 


I am using Vaadin with it's openlayers addon
I am showing a map with about 10000 points and lines between them.
Vaadin started getting very sluglish

The Solution

Kiren Pillay suggested that I use JProfiler
So that is what I did.
I finally saw what in Vaadin was taking all the time.
getApplication() on the Panel was being called more than 50,000 times
isEnabled() was also being called on the same panel about the same amount of time.

These calls were very fast, but because of the shear number of requests, it was slowing my application down to a crawl.

So with the combination of  JProfiler and JRebel I could apply these changes without a restart!


// Snip
  
   Application app;
   public MyPanel( Application app){
       this.app = app;
   }

   @Override
    public boolean isEnabled(){
        return true;
    }

   @Override
    public Application getApplication(){
        return app;
    } 
 

The end result ?

A dramatic improvement in handing in the browser!


Tuesday, July 24, 2012

Your Java IDE, friend or foe ?

Your Java IDE, friend or foe ?


The new Eclipse Juno is released.
And surprise surprise, it's slow, and caused a couple of sleepless night for a friend of mine.

My advice to any new or experienced Java developer, try NetBeans 7.2.

I know Elcipse has had some of these features for ages, but
1) are they stable ?
2) Do you fear updating your ide ?
3) Is emotional attachment the biggest factor in your choice ?

Here are two videos. Copyright to Netbeans.




Original Netbeans 7.2 Overview







Original Netbeans TestNG , conditional breakpoints video



Monday, July 23, 2012

Production grade REST services


Writing a REST service in Java is easy, writing a production grade one is almost as easy :)

A simple service

// JSR 311 REST service
@Path("myservice")
public class MyDataLoaderREST {

    @PUT
    @Consumes({"application/json"})
    public void loadFile(String csvdata) {
      CSVReader reader = new CSVReader(new StringReader(data));
      String nextLine = reader.readNext();
      Customer c = new Customer( nextLine[0],nextLine[1]);
      em.persist(c);
    }

}

The above service will work, but it is not really production grade in my opinion.

1) It does not return a positive or negative value
2) If something goes wrong like the csv is malformed, it will be next to impossible to debug.

The solution simple service

1) Always return a result, never return a HTTP error, the end user will never be able to figure out what is wrong.
2) If something obvious and something not obvious go wrong, return the line where the error happened.
3) Also don't treat all exceptions in the same way. Catch a FileNotFoundException and a IOException, you may want to handle differently.
4) Catch the RuntimeException as a final resort
5) Write using TDD!

The test!

// A simple JUnit test for testing the import

public class TestMyDataLoaderREST {

    @Test

    public void testImportCustomer() throws IOException {

        MyDataLoaderREST importFile = new MyDataLoaderREST();

        NodeCalculationLoadResult calcResult = importFile.loadFile("1,2");

        Assert.assertTrue(calcResult.isSuccess());

   }

    @Test

    public void testImportCustomerNull() throws IOException {

        MyDataLoaderREST importFile = new MyDataLoaderREST();

        NodeCalculationLoadResult calcResult = importFile.loadFile(null);

        Assert.assertFalse(calcResult.isSuccess());//make sure an exception was not thrown

        Assert.assertEquals(1,calcResult.getlineNumber());//make sure it's not line 0

   }

The service

// The JSR 311 improved service

import au.com.bytecode.opencsv.CSVReader;

@Path("myservice")

public class MyDataLoaderREST {

    @PUT

    @Consumes({"application/json"})

    public CustomerResult loadFile(String csvdata) {

        int lineNumber = 0;// line number outside try to catch can use it

        try {

         

          CSVReader reader = new CSVReader(new StringReader(data));

          if (nextLine.length < 2) {

                    return new CustomerResult(false, 1, "Error reading at line " + lineNumber + " line should have two or more values");

                }

           while ((nextLine = reader.readNext()) != null) {

           }
            return new CustomerResult(false, -1, lineNumber +" lines parsed and imported");

         } catch (ParseException ex) {

            return new CustomerResult(false, lineNumber, "Error parsing data at line " + lineNumber + " " + ex.getMessage());

        } catch (NumberFormatException ex) {

            return new CustomerResult(false, lineNumber, "Error reading number at line " + lineNumber + " " + ex.getMessage());

        } catch (RuntimeException ex) {

            return new CustomerResult(false, lineNumber, "Programmatic error reading number at line " + lineNumber + " " + ex.getMessage());

        }

    }

}


The domain Class @XmlRootElement
@Data // Project Lombok does all my getters and setters for me

// The domain object

@Data // Project Lombok does all my getters and setters for me

public CustomerResult {

     private boolean success;

     private int lineNumber;

     private String errorMessage;

     private Customer customer;

     public CustomerResult(boolean success , int lineNumber,String errorMessage){

       this.success = success;

       this.lineNumber = lineNumber;

       this.errorMessage = errorMessage;

      }

      public CustomerResult(Customer customer){

         this.customer = customer;

      }

      

}


Tuesday, July 3, 2012

What happened to POI

I had to read a XLSX file in POI today

Problem 1:
You can no longer use the old
HSSFWorkbook wb     = new HSSFWorkbook(fileInputStream); 
syntax
or you will get :

The supplied data appears to be in the Office 2007+ XML. You are calling the part of POI that deals with OLE2 Office Documents. You need to call a different part of POI to process this data (eg XSSF instead of HSSF)
org.apache.poi.poifs.filesystem.OfficeXmlFileException: The supplied data appears to be in the Office 2007+ XML. You are calling the part of POI that deals with OLE2 Office Documents. You need to call a different part of POI to process this data (eg XSSF instead of HSSF)

Problem 2:
So I tried to use the new API
Workbook workbook = WorkbookFactory.create(fileInputStream);

But where is org.apache.poi.ss.usermodel.WorkbookFactory ??

This is because you need another dependably now. Go figure.

        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.8</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.8</version>
        </dependency>


Problem 3:

So as a 'good' Java dev, I started with unit testing, but I did not want to read a file in my JUnit test.
I came across this : http://stackoverflow.com/questions/2597271/easy-to-get-a-test-file-into-junit

My JUnit now looks like :

public class TestCalculator {

    @Rule
    public ResourceFile res = new ResourceFile("/Comparative.xlsx");// this file is in my test resources

    @Before
    public void before() throws IOException{
        Assert.assertNotNull( res.getFile());
    }
    @Test
    public void testParseXLSDoc(){
        Calculator c = new Calculator(res.file.getAbsolutePath());//the Java File
        c.parseActiveDocument();  
    }
}

//from stackoverflow
public class ResourceFile extends ExternalResource {

    String res;
    File file = null;
    InputStream stream;

    public ResourceFile(String res) {
        this.res = res;
    }

    public File getFile() throws IOException {
        if (file == null) {
            createFile();
        }
        return file;
    }

    public InputStream getInputStream() {
        return stream;
    }

    public InputStream createInputStream() {
        return getClass().getResourceAsStream(res);
    }

    public String getContent() throws IOException {
        return getContent("utf-8");
    }

    public String getContent(String charSet) throws IOException {
        InputStreamReader reader = new InputStreamReader(createInputStream(),
                Charset.forName(charSet));
        char[] tmp = new char[4096];
        StringBuilder b = new StringBuilder();
        try {
            while (true) {
                int len = reader.read(tmp);
                if (len < 0) {
                    break;
                }
                b.append(tmp, 0, len);
            }
            reader.close();
        } finally {
            reader.close();
        }
        return b.toString();
    }

    @Override
    protected void before() throws Throwable {
        super.before();
        stream = getClass().getResourceAsStream(res);
    }

    @Override
    protected void after() {
        try {
            if (stream != null) {
                stream.close();
            }
        } catch (IOException e) {
            // ignore
        }
        if (file != null) {
            file.delete();
        }
        super.after();
    }

    private void createFile() throws IOException {
        file = new File(".", res);
        InputStream stream = getClass().getResourceAsStream(res);
        try {
            file.createNewFile();
            FileOutputStream ostream = null;
            try {
                ostream = new FileOutputStream(file);
                byte[] buffer = new byte[4096];
                while (true) {
                    int len = stream.read(buffer);
                    if (len < 0) {
                        break;
                    }
                    ostream.write(buffer, 0, len);
                }
            } finally {
                if (ostream != null) {
                    ostream.close();
                }
            }
        } finally {
            stream.close();
        }
    }
}