Advertisement

Sri Lanka's First and Only Platform for Luxury Houses and Apartment for Sale, Rent

Friday, October 19, 2012

Best Practice when XML Content Writing to Files

For performance, there are many developers who create XML content using traditional StringBuffer or StringBuilder by appending values with start and end tags. This has a performance advantage than using a XML Library API to generate XML both memory wise as well as Computation wise. But many developers don't know a side effect which can occur by using this method.

For example if you create the XML content by appending strings and use the following

        StringBuilder xml = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
        xml.append("<envelope>");
        xml.append(String.format("<header>%s</header>", "Important"));
        xml.append(String.format("<body>%s</body>", "Hello, World!"));
        xml.append("</envelope>");
        BufferedWriter bw = null;
        try {
            bw = new BufferedWriter(new FileWriter("message.xml"));
            bw.write(xml.toString());
        } catch(Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if(bw != null) {
                    bw.close();
                }
            } catch (IOException e) {                
                e.printStackTrace();
            }
        }

The above code will work as long as for content of XML you have Characters which are accepted by the default character set of the Operating System you used to execute this code with. If the character set is not "UTF-8" as soon as you have something like this "CAFÉ" in your XML Content, the XML will be corrupted and will not be able to opened up using web browsers and cannot be parsed using any parsing API.

To fix this you can either ensure you will never have characters outside of the default character set of the Operating System or if you want "UTF-8" by any means, you can change the content writing as following which will fix the issue.

        try {
            FileOutputStream fos = new FileOutputStream("message.xml");
            bw = new BufferedWriter(new OutputStreamWriter(fos, "UTF8"));
            bw.write(xml.toString());
        } catch(Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if(bw != null) {
                    bw.close();
                }
            } catch (IOException e) {                
                e.printStackTrace();
            }
        }

In this scenario we are explicitly saying that we need the content to be written in UTF8 Character set using OutputStreamWriter.

Friday, October 5, 2012

Usage of ThreadLocal in Java

The ThreadLocal class is an important yet often neglected class in the java default library. Many developers don't understand the usage of this class so this is my attempt to explain it.

The definition of this class in official javadoc is

"This class provides thread-local variables. These variables differ from their normal counterparts in that each thread that accesses one (via its get or set method) has its own, independently initialized copy of the variable"

So according to the definition if an Instance of ThreadLocal variable is accessed by different threads each thread will get a copy of the variable which is not shared or visible by other threads. Simply put this class enables Thread confinement of variables. The usual approach developers use to have independent variables in different threads is they initialize and assign each thread an object instance which implements Runnable or extends Thread where the required variable is an instance variable in that object. 

But ThreadLocal is ideal where you want to initialize one object and assign them to different threads yet have independent variables. The following example shows the class at work.

public class ThreadLocalTest implements Runnable {
    private static ThreadLocal<Integer> no = new ThreadLocal<Integer>() {
        public Integer initialValue() {
            return 0;
        }
    };
    
    public static void main(String[] args) {
        Thread t1 = null;
        // Single Object
        ThreadLocalTest test = new ThreadLocalTest();
        for(int i=0;i<10;i++) {
            // test object is used in 10 Threads
            t1 = new Thread(test);        
            t1.start();
        }        
    }
    
    public void run() {
        System.out.printf("Before %s : %d\n", Thread.currentThread().getName(), no.get());
        no.set(no.get() + 1);
        System.out.printf("After %s : %d\n", Thread.currentThread().getName(), no.get());
    }
}

Only one object is created and used in 10 different threads yet each thread has its own initialized variable 'no'.

Saturday, September 29, 2012

Google Code Jam 2012 Practice - Reverse Words

In order to improve my algorithm skills I wanted to try out some practice challenges offered by Google Code Jam 2012. I wrote the following code to solve Reverse Words challenge. I verified the output by submitting them to Google Code Jam page and there are correct.

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

/**
 * 
 * @author Shazin Sadakath
 *
 */
public class CodeJamSolution2 {
    private File inFile;
    private File outFile;
    
    public static void main(String[] args) {
        if(args.length < 2) {
            System.out.println("Usage : java CodeJamSolution2 <In File> <Out File>");
            return;
        }
        CodeJamSolution2 cjs2 = new CodeJamSolution2(args[0], args[1]);
        cjs2.start();
    }
    
    public CodeJamSolution2(String inFile, String outFile) {
        this.inFile = new File(inFile);
        this.outFile = new File(outFile);
    }
    
    public void start() {
        BufferedReader br = null;
        BufferedWriter bw = null;
        try {
            br = new BufferedReader(new FileReader(inFile));
            bw = new BufferedWriter(new FileWriter(outFile));
            int count = Integer.parseInt(br.readLine());
            String[] words = null;
            for(int i=0;i<count;i++) {
                words = br.readLine().split(" ");
                reverse(words);
                bw.write(String.format("Case #%d: %s\n", i+1, output(words)));
            }
        } catch(Exception e) {
            e.printStackTrace();
        } finally {
            if(br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            if(bw != null) {
                try {
                    bw.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
    
    /**
     * Method to reverse a word array
     * works at O(N / 2) 
     * 
     * @param words
     */
    public void reverse(String[] words) {
        int i=0;
        int j=words.length - 1;
        String temp = null;
        while(i < j) {
            temp = words[i];
            words[i] = words[j];
            words[j] = temp;
            i++;
            j--;
        }
    }
    
    /**
     * method to append all the elements in the array together
     * 
     * @param words 
     * @return appended words sentence
     */
    private String output(String[] words) {
        StringBuffer sb = new StringBuffer();
        for(int i=0;i<words.length;i++) {
            sb.append(words[i]);
            if(i != words.length - 1) {
                sb.append(" ");
            }
        }
        return sb.toString();
    }
}

Wednesday, September 26, 2012

Google Code Jam 2012 Practice - Store Credit

In order to improve my algorithm skills I wanted to try out some practice challeges offered by Google Code Jam 2012. I wrote the following code to solve Store Credit challenge. I verified the output by submitting them to Google Code Jam page and there are correct.

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Store Credit solution 
 * 
 * @author Shazin Sadakath
 *
 */
public class CodeJamSolution1 {
    private File inFile;
    private File outFile;
    
    public static void main(String[] args) {
        if(args.length < 2) {
            System.out.println("Usage : java CodeJamSolution1 <In File> <Out File>");
            return;
        }
        CodeJamSolution1 cjs1 = new CodeJamSolution1(args[0], args[1]);
        cjs1.start();
    }
    
    public CodeJamSolution1(String inFile, String outFile) {
        this.inFile = new File(inFile);
        this.outFile = new File(outFile);
    }
    
    public void start() {
        BufferedReader br = null;
        BufferedWriter bw = null;
        try {
            br = new BufferedReader(new FileReader(inFile));
            bw = new BufferedWriter(new FileWriter(outFile));
            int totalRecords = Integer.parseInt(br.readLine());
            int credit = 0;
            int items = 0;
            Map<String, List<Integer>> map = new HashMap<String, List<Integer>>();            
            for(int i=0;i<totalRecords;i++) {
                credit = Integer.parseInt(br.readLine());
                items = Integer.parseInt(br.readLine());
                int[] values = new int[items];
                String line = br.readLine();
                int j=0;
                List<Integer> indexes = null;                
                for(String value:line.split(" ")) {
                    values[j] = Integer.parseInt(value);                    
                    indexes = map.get(value);
                    if(indexes == null) {
                        indexes = new ArrayList<Integer>();
                    }
                    indexes.add(j);
                    map.put(value, indexes);
                    j++;
                }                
                insertionSort(values);
                int[] result = findSum(values, credit);    
                int[] finalValues = null;
                if(result[0] == result[1]) {
                    indexes = map.get(String.valueOf(result[0]));
                    finalValues = new int[] { indexes.get(0) + 1, indexes.get(1) + 1};
                } else {
                    finalValues = new int[] { map.get(String.valueOf(result[0])).get(0) + 1, map.get(String.valueOf(result[1])).get(0) + 1};
                    insertionSort(finalValues);
                }                
                bw.write(String.format("Case #%d: %d %d\n", i+1, finalValues[0], finalValues[1]));
                map.clear();                
            }
            
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if(br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            if(bw != null) {
                try {
                    bw.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
         
    }
    
    /**
     * Method to find sum
     * uses O(N) in worse case given a sorted array
     * 
     * @param values - int Array
     * @param sum - Sum
     * @return int Array with values which add to sum 
     */
    public int[] findSum(int[] values, int sum) {
        int[] result = null;        
        int i = 0;
        int j = values.length - 1;
        while(i <= j) {            
            if((values[i] + values[j]) == sum) {
                result = new int[] { values[i], values[j] };
                break;
            } else if ((values[i] + values[j]) < sum) {
                i += 1;
            } else if ((values[i] + values[j]) > sum) {
                j -= 1;
            }
        }        
        return result;
    }
    
    /**
     * insertion sort algorithm 
     * uses O(N ^ 2) is worse case
     * 
     * @param values - int Array to be sorted
     */
    public void insertionSort(int[] values) {
        int iHole = 0;        
        int item = 0;
        for(int i=1;i<values.length;i++) {
            item = values[i];
            iHole = i;
            while(iHole > 0 && values[iHole - 1] > item) {
                values[iHole] = values[iHole - 1];
                iHole -= 1;
            }
            values[iHole] = item;
        }        
    }    
}

Monday, September 24, 2012

Vulnerability in Opencart based shopping carts

I found a vulnerability which exposes the sensitive information stored in error log file of opencart web application to public. An unprotected web site will cause the log file to be crawled by legitimate bots and will be indexed in search engine result pages. For example if you want to what are the web sites which uses opencart web application as their main shopping cart application just use the following query in google and search.

PHP Warning:  unlink(system/cache/cache.currency [<a href='function.unlink'>function.unlink</a>]: No such file or directory in public_html/system/library/cache.php

This is common warning message logged by almost all of the opencart web applications in their log file. Along with this log file you can find usernames, directory structures etc which are sensitive. An unprotected system and system/log directory in opencart causes this vulnerability. This can be fixed by performing the following step as mentioned in sitefixit.

Securing The /system/ Folder

Certain files are wide-open by default. If you have installed OpenCart in your root directory, just go to http://www.yourdomain.com/system/logs/error.log and you should be able to download your error log, even if you’re a public user. You should protect these files, so create a .htaccess with the following code:


     <Files *.*>
    Order Deny,Allow
    Deny from all
    </Files> 

Then put that .htaccess file in the following 2 directories:
  1. /system/
  2. /system/logs/

Wednesday, September 12, 2012

How I didn't get the Amazon.com Job

Well I was informed by Kristin yesterday (12/09/2012) that there are pursuing with other candidates but I might be considered for future opportunities. Well I am not sad because I took out of good experience through these interviews on what to expect, where should I improve myself on.

One of the main problems I think that got me out of the interview process is that, I didn't ask enough questions from the interviewer. I was trying to find the solution to the problem as quickly as possible. As I think the two algorithms I wrote are in first and last phone screens were not what the interviewers were expecting. Amazon is a company working with millions of records and transactions per day so they might expect their algorithms to be much more efficient than O(n^2). The interviewer never told me this but I guess it is my fault I should have asked.

But I am pretty sure that I did really well during the second phone screen and wrote a very effient solution for the take home question given to me by Pascal. Pascal himself replied to me commending about the cleaness of the code.I am happy and proud about that.

But there are a lot of skills that I should master and this was a good wake up call. Hopefully I work hard on my weaknesses and become good in the future. Anyway as always thank god for giving me the opportunity.


Thursday, August 30, 2012

Amazon.com Interview!!!! Yeah you heard it, Amazon.com! - 3

Thanks to almighty god, I was contacted by Kristin on Friday (24/08/2012) and invited for the 3rd interview which was held on today (30/08/2012).

A Software Development Engineer named Armin contacted me and as usual he asked some general questions followed by technical questions.One of the main questions was;

Given integer array and number k find the two numbers in the array which will add up and become equal to k

The solution I wrote was as below.

int [] inA = new int[6]{1,2,3,4,5,6};
int k = 2

 int[] find ( int[] inArray, int k ) {
     int n1, n2;
     outer:
     for(int i=0;i<inArray.length;i++) {
         for(int j=0;j<inArray.length;j++) {
             if((inArray[i] + inArray[j]) == k && i != j) {
                 n1 = inArray[i];
                 n2 = inArray[j];
                 break outer;
             }
         }
     }
     
     if(n1 == 0 && n2 == 0) {
         return null;
     }
     
     return new int[] { n1, n2 };
 }
The complexity is O(n^2) and Armin was ok with it. Then he asked me whether I have any questions and I asked about my prospective line of work there. He said it will be mostly Payment Transaction processing related development. Anyhow I am thankful to god for giving me this entire experience.