Monday, 26 January 2015

Resolving "The markup in the document following the root element must be well-formed" Exception

Background

In last post we say how we can efficiently parse an XML file using DocumentBuilder -


But as we had concluded that post saying we cannot parse an XML file with multiple root elements. Hence in this post we will see how we can achieve that.

To The Code....

Let say now our data.xml file looks like the following - 

<data key="name" value="John"></data>
<data key="age" value="23"></data>
<data key="sex" value="male"></data>

That is no root element (or rather 3 root elements). If we run the previous code here we will get following Exception -

[Fatal Error] data.xml:2:2: The markup in the document following the root element must be well-formed.
Exception in thread "main" org.xml.sax.SAXParseException; systemId: file:/C:/Users/athakur/newJavaWorkspace/XMLParserDemo/data.xml; lineNumber: 2; columnNumber: 2; The markup in the document following the root element must be well-formed.
    at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(Unknown Source)
    at javax.xml.parsers.DocumentBuilder.parse(Unknown Source)
    at XMLParser.main(XMLParser.java:24)


Now lets see how can we tackle this. In this case we will take help of java.io.SequenceInputStream.


import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.SequenceInputStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 * 
 * @author athakur
 *
 */
public class XMLParser {
    
    public static void main(String args[]) throws IOException, ParserConfigurationException, SAXException
    {
        File file = new File("data.xml");
        DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
        Enumeration<InputStream> streams = Collections.enumeration(
                Arrays.asList(new InputStream[] {
                    new ByteArrayInputStream("<ROOT>".getBytes()),
                    new FileInputStream(file),
                    new ByteArrayInputStream("</ROOT>".getBytes()),
                }));

        SequenceInputStream sequenceStream = new SequenceInputStream(streams);
        Document doc = db.parse(sequenceStream);
        NodeList nodes = doc.getElementsByTagName("data");
        for ( int i = 0; i < nodes.getLength(); i++) 
        {
            Element element = (Element) nodes.item(i);
            String key = element.getAttribute("key");
            String value = element.getAttribute("value");    
            System.out.println("Key : " + key + " || Value : " + value);
        }
    }
}
 

and life is good again! Output is -

Key : name || Value : John
Key : age || Value : 23
Key : sex || Value : male 



Related Links

Parsing XML files in Java using javax.xml.parsers.DocumentBuilder

Background

If you want to read xml files and process tag and attributes then there is a smarter way to do it than just reading the file line by line. That is exactly what we are going to see in this post.

To the Code.....

Assume we have the following data.xml file in the root directory of the project with following contents - 

<ROOT>
    <data key="name" value="John"></data>
    <data key="age" value="23"></data>
    <data key="sex" value="male"></data>
</ROOT>


Our goal is to parse this file and print key and value in an efficient manner. We do it the following way - 

import java.io.File;
import java.io.IOException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 * 
 * @author athakur
 *
 */
public class XMLParser {
    
    public static void main(String args[]) throws IOException, ParserConfigurationException, SAXException
    {
        File file = new File("data.xml");
        DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
        Document doc = db.parse(file);
        NodeList nodes = doc.getElementsByTagName("data");
        for ( int i = 0; i < nodes.getLength(); i++) 
        {
            Element element = (Element) nodes.item(i);
            String key = element.getAttribute("key");
            String value = element.getAttribute("value");    
            System.out.println("Key : " + key + " || Value : " + value);
        }
    }
}

and the output is as expected - 

Key : name || Value : John
Key : age || Value : 23
Key : sex || Value : male

Easy... wasn't it? Using DocumentBuilder makes parsing xml files easy.

NOTE : The XML file should have only one root element and can have multiple child elements. If this is not satisfied you will get following Exception

org.xml.sax.SAXParseException: The markup in the document following the root element must be well-formed.

In case of such cases (multiple root elements) how can we parse the XML? I have explained the same in separate post (See Related Links section below)

Parsing XML String

For parsing Simple XML strings you can do - 

import java.io.IOException;
import java.io.StringReader;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;


public class StringXMLParser {
    
    public static void main(String args[]) throws SAXException, IOException, ParserConfigurationException {
        
            String xmlString = "<records><employee><name>Aniket</name><title>Software Developer</title></employee></records>";
            
            DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
            Document doc = db.parse(new InputSource(new StringReader(xmlString)));
            
            NodeList nodes = doc.getElementsByTagName("employee");

            for (int i = 0; i < nodes.getLength(); i++) {
              Element element = (Element) nodes.item(i);

              NodeList name = element.getElementsByTagName("name");
              Element line = (Element) name.item(0);
              System.out.println("Name: " + line.getFirstChild().getNodeValue());

              NodeList title = element.getElementsByTagName("title");
              line = (Element) title.item(0);
              System.out.println("Title: " + line.getFirstChild().getNodeValue());
            }
    }
}

Related Links



Saturday, 24 January 2015

Getting started with IBM Bluemix

Background

A while ago I had written a post explaining difference between SaaS, PaaS and IaaS.

In PaaS if you see examples IBM Bluemix is one of the PaaS solutions. In this post we will explore it in detail. Bluemix is powered by Cloud Foundry open source project which itself is a PaaS solution.

For more details on why you should use IBM bluemix, what are the benefits you can refer to following slideshare PPT -


Getting Started

You can sign in into Bluemix portal with following URL - 

You will need an IBM ID for the same. If you don't have you can create one. Once you login you should see following dashboard section -


 Once you have the Dashboard you are all set to create and deploy App of your own. Go ahead and Click on Create An App.

Creating an App

  • Click on Create An App



  • You will be prompted to choose what type of App are you creating ? Is it a web app or a mobile App? For this demo tutorial lets select web app.
  • Next on selecting WEB you will get options to select from various runtimes like Java, NodeJS etc...


  •  For this demo I am choosing NodeJS as it will be easier to demonstrate final outputs. Choose SDK for Node js and click continue.
  • You will then be asked to enter App Name. This will for unique root to your Application. So if some name is already taken you have to give another one (just like domain names :) )


  •  Put some name. I had put DemoWebApp but unfortunately it was taken. So I have put it as DemoTestWebApp. We will see it is next screenshots. Anyway click on finish and your template App should be created, built and deployed.



  • Let see how it looks like, shall we?

See the Route field in above screenshot? That is unique url that points to your App. Go ahead click on it or copy paste it in the URL of your favorite browser. You should see following -


  •  Yeah we create our template App...big deal? What the fun unless we modify it and give it our flavor :)

Modifying and deploying your own code

If you see start coding section under dashboard you should see various methods in which you can build your code.

  •  Yes it provides seamless integration with GIT. Fell free to try out any/all methods. For this demo I am going to use the CF (Cloud foundry) CLI(command line interface). This section gives you list of exact steps that you need to do for creating a local copy of code, changing it and deploying it. But will  re do them for better understanding -

    • Download and install CF CLI from here. I am using Windows. You can choose installer which suits your requirement.... Debian, Redhat, Mac OS X, Windows etc.
    • To verify that it is correctly installed you can simple type cf -v in your command line and it should print you the version. For me it gives -

      C:\Users\athakur>cf -v
      cf version 6.9.0-620f841-2015-01-20T18:01:40+00:00
    • Next Download the template code. Link to it should be in the same CF CLI section of  Start coding section. Go ahead and download the zip file (DemoTestWebApp.zip in my case) and extract it.
    • Lets make some changes to the code now. Example code makes use of Jade Node template engine. The pages that are rendered are in views folder of extracted folder.
    • I have changed some line of code in body.jade file.  For the changes that I made and how can we deploy these changes see following screenshots - 

body.jade File Content

//- body.jade
//- This file provides the HTML body part.


body
  table
    tr
      td(style= "width:30%;" )
        img(src="/images/newapp-icon.png")
      td
        h1 Welcome to Bluemix!
        p This is a demo web app created with <span class = "blue">NodeJS Starter Application</span> by <span class = "blue">Aniket Thakur</span>. Happy Coding!



Now lets deploy our code -

  • Navigate to App directoru ->  cd C:\Users\athakur\Sources\WebTestAppDemo
  • Next connect to bluemix -> cf api https://api.ng.bluemix.net 
  • Login -> cf login -u yourUserName
  • Setup target -> cf target -o yourOrganization -s yourSpace
  • Finally push your code -> cf push DemoTestWebApp 

Finally you should see something like -


1 of 1 instances running

App started


OK

App DemoTestWebApp was started using this command `node app.js`

Showing health and status for app DemoTestWebApp in org *********** / space at
hakur as *************...
OK

requested state: started
instances: 1/1
usage: 128M x 1 instances
urls: demotestwebapp.mybluemix.net
last uploaded: Sun Jan 25 06:28:12 +0000 2015

     state     since                    cpu    memory          disk
#0   running   2015-01-25 11:59:01 AM   0.0%   18.1M of 128M   35.9M of 1G



This means your code is deployed and your app is restarted. All you have to do now is revisit your App URL and test out the changes.


  Lastly I would say it always fun to try new technologies. So do give this a try. It will surely make your life easier (it terms of app deployment and maintenance ofcourse :) )


Related Links

Understanding SOA (Service Oriented Architecture)

Background



Lets say you are designing a system to process stock rates that you receive from stock exchange. Lets say you develop a web application that expects a JSON object. Maybe in further processing down the workflow some other format is expected. To integrate various such services and inter communicate in platform independent way SOA is used. SOA suites provides easy way to integrate such services.



SOA and ESB

SOA is service oriented architecture. In SOA services are decoupled and can interact with each other irrespective of the service type. Meaning a particular service can be platform or protocol specific but SOA enables such services to interact and exchange data. This data is essentially exchanged via ESB (Enterprise service bus) which forms the backbone of any SOA architecture.

Let me go ahead and give specific example to help understand this better. One way ESB could be implemented us by using JMS servers and using XML/XSD as means of transferring data between various services. So various service will register or connect to these JMS servers and exchange data using XML format. Generally SOA suite comes bundles with so called adapters that help transforming messages to and from format understood by service and XML.

For example consider shares trading system. Messages from stock exchange come in FIX protocol. You may have build an application that expects JSON. To make these both systems work you will use SOA - FIX Adapter will convert FIX message to XML, then this xml will be transferred to JSON Adapter over ESB which will then convert to JSON as required by your system endpoint.

Note : I have mentioned XML as it is platform independent message format. It is in fact SOAP (Simple Object access Protocol) that is used to transfer messages. SOAP is a standardized xml with already defined and recognized specifications.

Finally hoping following picture makes it very clear.




Related Links

Friday, 23 January 2015

Difference between SaaS, PaaS and IaaS explained

Background

When decision is made that the business you are trying to create depends on cloud services you need to choose between one of the following deployment models - 
  • IaaS (Infrastructure as a Service)
  • PaaS (Platform as a Service)
  • SaaS (Software as a Service)

Simply speaking following diagram should tell you what each model represents -


Lets discuss in details about each of the cloud models  -

 SaaS (Software as a Service)

SaaS is the simplest cloud service model that serves the end users. All end users have to do is log into the cloud service from a client (typically a browser) and start using the service - Excellent example here would be GMail . All you do is log into your gmail account and send/receive mails.

Target Audience : End Users

Benefits : It saves you the trouble of creating and maintaining software's by yourself. I gave Gmail as an example for SaaS above. Now think you are starting your own business/company and you need to communicate via emails.  If you start from scratch you will have to have your own mail server, configuration and most importantly it's maintenance . SaaS lets you delegate this to 3rd party (SaaS vendors) - Gmail in our example. 

Working : SaaS generally works on Subscription model. You pay for the duration of time you are using the services. Some SaaS based companies may give out free trials for some trial period or give some basic features for free to end users to try out. For example Gmail - if you exceed the space quota available you have to pay for the extra space.

Example : Look around you -  the services that you use in day to day life. Gmail, Salesforce, DropBox, Cisco WebEx, Google Forms, Google Docs, Microsoft 365 etc.





PaaS (Platform as a Service)


PaaS comes at a level lower than SaaS. PaaS allows you to deploy your code without bothering about underlying runtime ,operating system or server infrastructure. Best example here would be - Google App Engine . You choose what programming language suits your business model - Java, NodeJs, PHP ... , write code and deploy it on the PaaS provider. 

Target Audience : Developers

Benefits : It saves you the trouble of owning and maintaining servers (data centers), operating systems on it, runtimes needed to build and deploy your application etc. PaaS delegates these infrastructure requirements to 3rd party (PaaS vendors) - Google App Engine in our example.Also you don't have to worry about scaling and performance. 

Working : So lets say you have written a code for the service you want to provide but dont want to bear the additional cost of purchasing and maintaining infrastructure required to build and deploy your code. So you go to a PaaS vendor and deploy your code there. Again this is pay as you use model. You will have some memory space / RAM  allotted to you for free. As your application scales, your customer base increases you will have to pay for that. Best thing about this is that you don't have to pay unless your requirements exceed the ones provided by the PaaS vendor.

Example :Unless you are a developer I don't expect you to know these but here are some example - Google App EngineCloud Foundry, Heroku, IBM Bluemix, Red Hat’s OpenShift.



 IaaS (Infrastructure as a Service)

This is the lowest level of cloud services that are provided. This saves you the trouble of actually buying and maintaining server infrastructure. In this you get servers from IaaS vendor. You choose your own OS, your runtimes, your application code etc (Refer to topmost picture to visualize).  Famous example of this is AWS (Amazon web services).


Target Audience : Typically IT Admins

Benefits : It saves you the overhead of maintaining hardware infrastructure. You directly get the servers from IaaS vendor.

Working : This generally works using virtual environments. IaaS vendor will have data centers each having multiple servers. Each server will have multiple virtual machines running on them and each IaaS customer will get such a virtual machine. You can then decide what OS you prefer, what runtimes you need etc. Note  as a IaaS customer you will get the experience of a full server + OS stack. You will never know that it infact is virtual environments. How this actually works will of-course depend on the vendor. As far as AWS goes you can try it out for one year without any charges with specified data limits. After a year you will be charged.

Example :Examples for IaaS vendors are AWS, HPCloud, CloudSigma etc.


Summary

 To summarize each of these cloud models have their own uses, So choose according to your business model.


Sunday, 18 January 2015

Factory Method and Abstract Factory Pattern

Background

We know design patterns are broadly categorized into three types - 
  1. Creational
  2. Structural
  3. Behavioral
In this post we will see Factory pattern/Factory method and Abstract Factory design patterns which falls under creational design pattern.
One of the most basic OOP principle is  - "Program to an interface not an implementation". This means you should not directly instantiate your object with new operator in your classes. But then that is how we create new objects in Java. Don't we?  Correct! There is no escape from using new operator to instantiate object but we can surely abstract it out to decouple the object creation code.

That is the very purpose of Factory patterns to abstract out creation of Objects. 

  • All Factory patterns encapsulate Object creation.

Lets understand this with an example. 

Simple Factory pattern


Lets say you are running a sandwich store and want to write an API to deliver sandwiches as asked by the customers. 

public class SandwichStore {
   
    public Sandwich orderSandwich(String type)
    {
        Sandwich sw;
        if(type.equalsIgnoreCase("cheese"))
        {
            sw = new CheeseSandwich();
        }
        else if(type.equalsIgnoreCase("grill"))
        {
            sw = new GrillSandwich();
        }
        else
        {
            sw = new RegularSandwich();
        }
        sw.addToppings();
        sw.makeSlices();
        sw.pack();
        return sw;
    }
   
}

 where CheeseSandwich, GrillSandwich and RegularSandwich are concrete implementations of Sandwich class.

Notice code to add toppings, to slice it and packing remain same for all sandwiches. Only change is creating sandwiches depending on the order. Now if tomorrow you decide to add new types of sandwiches or remove existing ones you need to modify above code which is not correct. This is where the factory pattern comes into picture. Job of creating the sandwich is delegated to this factory. See code below -

public class SandwichFactory {
    
    public Sandwich createSandwich(String type)
    {
        Sandwich sw;
        if(type.equalsIgnoreCase("cheese"))
        {
            sw = new CheeseSanwich();
        }
        else if(type.equalsIgnoreCase("grill"))
        {
            sw = new GrillSandwich();
        }
        else
        {
            sw = new RegularSandwich();
        }
        return sw;
    }

}

and then our store would look like - 

public class SandwichStore {
    
    SandwichFactory sf = new SandwichFactory();
    
    public Sandwich orderSandwich(String type)
    {
        Sandwich sw = sf.createSandwich(type);
        sw.addToppings();
        sw.makeSlices();
        sw.pack();
        return sw;
    }
    
}
 

 Notice how we have successfully moved the sandwich creation dependency to new object (Factory). Also SandwichStore has no need now to know about various types of (sandwiches)Object creations. This is a simple Factory pattern.

Factory Method pattern

  • Factory Method pattern encapsulates object creation by letting subclass decide what object to create.

Above Sandwich store code with Factory Method will look something like - 

public abstract class SandwichStore {
   
    public Sandwich orderSandwich(String type)
    {
        Sandwich sw = createSandwich(type);
        sw.addToppings();
        sw.makeSlices();
        sw.pack();
        return sw;
    }
    
    public abstract Sandwich createSandwich(String type);
   
}

class ChineseSandwich extends SandwichStore
{

    @Override
    public Sandwich createSandwich(String type) {
        Sandwich sw;
        if(type.equalsIgnoreCase("cheese"))
        {
            sw = new ChineseCheeseSanwich();
        }
        else if(type.equalsIgnoreCase("grill"))
        {
            sw = new ChineseGrillSandwich();
        }
        else
        {
            sw = new ChineseRegularSandwich();
        }
        return sw;
    }
    
}

Abstract Factory pattern

  • Abstract Factory pattern provides an interface to create family of related objects.
  • Methods of abstract factory are generally Factory methods.
 Code for this would looke something like -

public  class SandwichStore {
    
    SandwichFactory sf;
   
    public SandwichStore(SandwichFactory sf) {
        this.sf = sf;
    }

    public Sandwich orderSandwich(String type)
    {
        Sandwich sw = sf.createSandwich(type);
        Sause sause = sf.createSause();
        sw.addToppings();
        sw.makeSlices();
        sw.pack();
        sw.addSause(sause);
        return sw;
    }
    
    public static void main(String args[])
    {
        SandwichStore sw = new SandwichStore(new ChinesSandwichFactory());
        sw.orderSandwich("cheese");
    }
}

class ChinesSandwichFactory extends SandwichFactory {

    @Override
    public Sandwich createSandwich(String type) {
        //Return Chines type sandwiches
    }
    
    @Override
    public void createSause() {
        //Return Chines type sause
    }
    
}

class IndianChinesFactory extends SandwichFactory {

    @Override
    public Sandwich createSandwich(String type) {
        //Return Indian type sandwiches
    }
    
    @Override
    public void createSause() {
        //Return Indian type sause
    }
    
} 




Note : The createSandwich() and  createSause() methods are in fact a Factory methods. As stated previously each method of Abstract Factory is a Factory Method.

Generally Abstract Factory class will have many such Factory methods each creating unique object of a family of products. Hence Multiple such methods create families of related products (each product corresponding to each factory method).

Note : Above code creates Family of Sandwiches and Family of sauses which are related (we add sause to the sandwich).






In above diagram each product (product1, product2 ...) corresponds to a factory method in Abstract factory (which is implemented uniquely in Factory1, Factory2...)


Difference between  Factory Method and Abstract Factory

  • Factory Method is a single method (perhaps abstract) that uses inheritance to delegate object creation.
  • Abstract Factory is reference to abstract class whose subclass instances create actual objects. Each concrete implementation of abstract factory creates related products having same super class (interface).
  • AbstractFactory pattern uses composition to delegate responsibility of creating object to another class while Factory design pattern uses inheritance and relies on derived class or sub class to create object.






Related Links

Thursday, 8 January 2015

Understanding Localization in Java

Background

Localization is a very important concept. Generally when you write a application or create a website you do it in a particular language Eg. English. But customers of your application/website may be from different country understanding different languages. In fact English itself has may variation. For Eg. you have US English, British English, Indian English etc To make you application/website dynamic to the customers locale understanding and implementing Localization is very important.


In this post I will show basics of localization , classes used in Java.

Locale class

Locale class is used in Java as basis of deciding which locale your program uses. To get all available locales that is supported in the JVM you are running you can run the following code - 

    public static void main(String args[])
    {
        for(Locale locale : Locale.getAvailableLocales())
        {
            System.out.println(locale);
        }
    }


I am not providing output for above as the list is big. Lets see a shorter version of this. Lets see all locales of languages english. Before that's lets understand locale.  you can imagine locale as language specs that people of certain region understand. You can identify locale as  (language + country +variant [if any]). Consider variants as same language different variation. In terms of databases this is the primary key. We will see this in more details in some time. But for now lets come to Locale class. So I was saying following code will show all locales of english language (but different country or variants if any).

    public static void main(String args[])
    {
        for(Locale locale : Locale.getAvailableLocales())
        {
            if(locale.getLanguage().equals("en"))
            {
                System.out.println(locale + " : " + locale.getDisplayName());
            }
        }
    }

and the output is :

en_MT : English (Malta)
en_GB : English (United Kingdom)
en_CA : English (Canada)
en_US : English (United States)
en_ZA : English (South Africa)
en : English
en_SG : English (Singapore)
en_IE : English (Ireland)
en_IN : English (India)
en_AU : English (Australia)
en_NZ : English (New Zealand)
en_PH : English (Philippines)


You can get the default locale using Locale.getDefault() method where as you can set default locale using Locale.setDefault(yourLocaleObject); 

You can create locale class in following ways -

  1. Locale locale = new Locale("en", "", ""); 
  2. Locale locale = Locale.forLanguageTag("en");
  3. Locale locale = new Locale.Builder().setLanguageTag("en").build(); 
  4. Locale locale = Locale.ENGLISH;

Programatically speaking locale can be of following format

language + "_" + country + "_" + (variant + "_#" | "#") + script + "-" + extensions

Resource Bundles

Resource Bundles are entities used to map keys to values in different locales. We can simply load or get a resource bundle and then call get on some key to get the locale specific value and show it to the user. We will see this in detail code in some time.

ResourceBundle is an abstract class. It has two derived classes - 

  1. PropertyResourceBundle
  2. ListResourceBundle

In  PropertyResourceBundle we essentially provide property files - one for each locale containing locale specific values. When this resource bundle is loaded and get is called keys from the property file corresponding to locale supplied is fetched and returned.

In ListResourceBundle property file is replaced by Classes. classes that extend ListResourceBundle class and override getContents() method, which returns an Object [][].

 
Code to understand PropertyResourceBundle 

Create project structure as follows -



Add following content in propertied file.

Contents of ResourceBundle_en.properties
HW = "Hello World in English!"

Contents of ResourceBundle_fr.properties
HW = "Hello World in French!"

Contents of ResourceBundle_it.properties
HW = "Hello World in Italian!"

Contents of ResourceBundle.properties
HW = "Hello World!"

and execute the following code - 

import java.util.Locale;
import java.util.ResourceBundle;


public class LocalizationTest {
    
    public static void main1(String args[])
    {

        
        System.out.println("Setting Default locale : " + Locale.getDefault());
        System.out.println("Using Resource Bundle with locale : " + Locale.getDefault());
        ResourceBundle rb = ResourceBundle.getBundle("Resourcebundle", Locale.getDefault());
        System.out.println("HW : " + rb.getString("HW"));
        System.out.println("-----------------------------");
        
        Locale.setDefault(Locale.ITALIAN);
        System.out.println(" Setting Default locale : " + Locale.getDefault());
        System.out.println("Using Resource Bundle with locale : " + Locale.getDefault());
        rb = ResourceBundle.getBundle("Resourcebundle", Locale.getDefault());
        System.out.println("HW : " + rb.getString("HW"));
        System.out.println("-----------------------------");
        
        Locale.setDefault(Locale.FRENCH);
        System.out.println("Setting Default locale : " + Locale.getDefault());
        System.out.println("Using Resource Bundle with locale : " + Locale.getDefault());
        rb = ResourceBundle.getBundle("Resourcebundle", Locale.getDefault());
        System.out.println("HW : " + rb.getString("HW"));
        System.out.println("-----------------------------");
        
        /**
         * If resource bundle property file for given locale (GERMAN in this case) is 
         * not found then resource bundle property file of default locale is considered
         *  i.e FRENCH in this case
         */
        System.out.println("Using Default locale : " + Locale.getDefault());
        System.out.println("Using Resource Bundle with locale : " +  Locale.GERMAN);
        rb = ResourceBundle.getBundle("Resourcebundle", Locale.GERMAN);
        System.out.println("HW : " + rb.getString("HW")); 
        System.out.println("-----------------------------");
        
        /**
         * If resource bundle property file for given locale (GERMAN) is 
         * not found and neither for the default locale (CHINESE)
         * then property file with same name as resource bundle
         * base name(no language or country extensions) 
         * is picked up (ResourceBundle.properties)
         */
        Locale.setDefault(Locale.CHINESE);
        System.out.println("Setting Default locale : " + Locale.getDefault());
        System.out.println("Using Resource Bundle with locale : " +  Locale.GERMAN);
        rb = ResourceBundle.getBundle("Resourcebundle", Locale.GERMAN);
        System.out.println("HW : " + rb.getString("HW"));
    }

}

 and the output is :

Setting Default locale : en_US
Using Resource Bundle with locale : en_US
HW : "Hello World in English!"
-----------------------------
 Setting Default locale : it
Using Resource Bundle with locale : it
HW : "Hello World in Italian!"
-----------------------------
Setting Default locale : fr
Using Resource Bundle with locale : fr
HW : "Hello World in French!"
-----------------------------
Using Default locale : fr
Using Resource Bundle with locale : de
HW : "Hello World in French!"
-----------------------------
Setting Default locale : zh
Using Resource Bundle with locale : de
HW : "Hello World!"

Note : If properties file are not in the path or key is not found then MissingResourceException is thrown.

Similarly for Code to understand ListResourceBundle

// Italian version
public class ResourceBundle_it_IT extends ListResourceBundle {
    public Object[][] getContents() {
        return contents;
    }

    static final Object[][] contents = { 
        { "HW", "Hello World in Italian!" },
        { "GB", "Good bye in Italian" } 
    };
}

Resource Bundle is loaded in same way as Property resource bundle.

Note 1: However in case of ListResourceBundle you call resourceBundle.getObject("ABC") and the call returns an Object unlike the case of PropertyResourceBundle which returns String.

Note2 : Make sure Resource Bundle classes that extend ListResourceBundle  are public as java uses reflection to load these classes.

There are two main advantages of using a Java class instead of a property file for a resource bundle:
  • You can use a value type that is not a String.
  • You can create the values of the properties at runtime. 

You can print all values in your property resource using following Java 8 snippet -


Locale us = new Locale("en", "US");
ResourceBundle rb = ResourceBundle.getBundle("ResourceBundle", locale);
System.out.println(rb.getString("hello"));
Set<String> keys = rb.keySet();
keys.stream().map(k -> k + " " + rb.getString(k)).forEach(System.out::println);


or you can even use a Property (by converting ResourceBundle to property) advantage of which being you can give default value -


Properties props = new Properties();
rb.keySet().stream().forEach(k -> props.put(k, rb.getString(k)));
System.out.println(props.getProperty("propertyNotPresent")); //null
System.out.println(props.getProperty("propertyNotPresent", "Hello World!")); //123 



Resolution of Resource Bundles

A fully qualified resource bundle should be of following format - 

bundlename + "_" + language + "_" + country + "_" + (variant + "_#" | "#") + script + "-" + extensions

When you load a bundle with a locale a sequence is followed to resolve the bundle used. That is as follows - 

  1. The resolution starts by searching for an exact match for the resource bundle with the full name.
  2. If there is a tie between properties file and java file, java resource is given preference.
  3. The last part (separated by _) is dropped and the search is repeated with the resulting shorter name. This process is repeated till the last locale modifier is left.
  4. The search is restarted using the full name of the bundle for the default locale.
  5. Search for the resource bundle with just the name of the bundle.
  6. If all the above fails , then MissingBundleException is thrown.

Following diagram shows steps Java goes through when asked for resource bundle Zoo with the locale new Locale("fr", "FR") when the default locale is US English


Lets take a quick question then -

QQ > How many files Java would need to lookup for resource bundle with the followind code
    Locale.setDefault(new Locale("at"));
    ResourceBundle rb = ResourceBundle.getBundle("BundleResource", new Locale("en"));

The answer is six.

1. BundleResource_at.java
2. BundleResource_at.properties
3. BundleResource_en.java
4. BundleResource_en.properties
5. BundleResource.java
6. BundleResource.properties

NOTE* : Java isn’t required to get all of the keys from the same resource bundle. It can get them from any parent of the matching resource bundle. A parent resource bundle in the hierarchy just removes components of the name until it gets to the top.

For eg. for matching bundle

BundleResource_fr_FR.java

Java can key value from
  1. BundleResource_fr_FR.java
  2. BundleResource_fr.java
  3. BundleResource.java
and for BundleResource_fr.properties

  1. BundleResource_fr.properties
  2. BundleResource.properties


Note : The getBundle() method takes a ResourceBundle.Control object as an additional parameter.
You can extend ResourceBundle.Control class, override getCandidateLocales() method and pass it's instance  to the getBundle() method. By this you can change the default resource bundle search process. You can even read from other file formats (Eg. XML files).

Note :  All of the above classes are for String localization. This does not consider numbers or currency representation in different languages. You need to use Format abstract class for that. It's implementation include -
  1. NumberFormat
    1. getInstance()
    2. getIntegerInstance()
    3. getCurrencyInstance()
    4. getPercentageInstance()
  2. DateFormat (SimpleDateFormat)
    1. getDateInstance()
    2. getTimeInstance()
    3. getDateTimeInstance()
After you get an instance of above concrete classes you can call format() method to get locale specific string representation of data. If you want data back you can use corresponding parse() method.


NOTE :The format classes are not thread-safe. Do not store them in instance variables
or static variables. 

Note : Localization(l10n) and Internationalization(i18n) are two different concepts.
Internationalization is the process of designing and building an application to facilitate localization. Localization, in turn, is the cultural and linguistic adaptation of an internationalized application to two or more culturally-distinct markets.

For more on this see SO question in related Links section.

Related Links

Tuesday, 6 January 2015

Java File I/O (NIO.2)

Background

Initially all Java had for supporting Files was java.io.File class. But it lacked lot of functional features like copying file, handling symbolic links, getting attributes of file etc. As a result new set of I/O APIs were introduced in Java 7 called NIO.2 (New I/O).



We will see three important things in this post
  1. Path interface and it's functions
  2. FileVisitor (Walking a file tree)
  3. Directory WatchService (Watching a directory for changes)

 Understanding Path interface

Path is an interface in java.nio.file package. It extends 3 other interfaces
  1. Comparable<Path>
  2. Iterable<Path>
  3. Watchable
You can get instance of Path using methods defines in class java.nio.file.Paths . Following is the code to understand Path interface and it's methods -

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class HelloWorld {

    public static void main(String args[]) {

        Path p1 = Paths.get("C:\\Users\\.\\athakur\\Desktop\\..\\Desktop");
        Path p3= Paths.get("C:\\Users\\.\\athakur\\Desktop\\..\\Desktop\\abc.txt");
        Path p4 = Paths.get("C:\\Users\\athakur\\Desktop\\abc.txt");
        
        //GET methods
        System.out.println("File name : " + p1.getFileName());
        System.out.println("Root File : " + p1.getRoot());
        System.out.println("Name Count : " + p1.getNameCount());
        System.out.println("Get Name: " + p1.getName(2)); // thows java.lang.IllegalArgumentException if index is > getNameCount() - 1
        System.out.println("Get Parent: " + p1.getParent());
        
        for(Path p : p1) {
            System.out.println("Element : " + p);
        }
        
        //TO methods
        System.out.println("Uri : " + p1.toUri());
        System.out.println("File : " + p1.toFile());
        System.out.println("Normalize : " + p1.normalize());
        System.out.println("Absoulute  : " + p1.toAbsolutePath()); //absolute does not normalize
        
        try {
            System.out.println("RealPath  : " + p1.toRealPath());// Throw IOException if File does not exist
            //returns absolute normalized path
        } catch (IOException e) {
            e.printStackTrace();
        } 
        
        System.out.println(p3.equals(p4));
        System.out.println(p3.toAbsolutePath().equals(p4.toAbsolutePath()));
        
        try {
            System.out.println(p3.toRealPath().equals(p4.toRealPath()));
            //Make sure Paths are normalized and absolute before comparing
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        System.out.println("File exists : " + Files.exists(p1));
        
    }


}


Output :

File name : Desktop
Root File : C:\
Name Count : 6
Get Name: athakur
Get Parent: C:\Users\.\athakur\Desktop\..
Element : Users
Element : .
Element : athakur
Element : Desktop
Element : ..
Element : Desktop
Uri : file:///C:/Users/./athakur/Desktop/../Desktop/
File : C:\Users\.\athakur\Desktop\..\Desktop
Normalize : C:\Users\athakur\Desktop
Absoulute  : C:\Users\.\athakur\Desktop\..\Desktop
RealPath  : C:\Users\athakur\Desktop
false
false
true
true

Another interesting method is relativize()

        Path p5 = Paths.get("C:\\Users\\athakur\\Desktop");
        Path p6 = Paths.get("C:\\Users\\athakur\\Desktop\\Dir1\\abc.txt");
        
        System.out.println("p5 relative to p6 : " + p6.relativize(p5));
        System.out.println("p6 relative to p5 : " + p5.relativize(p6));


Output :

p5 relative to p6 : ..\..
p6 relative to p5 : Dir1\abc.txt

NOTE:
  • The relativize() method needs that both paths be relative or both be absolute. IllegalArgumentException will be throws if a relative path is used with an absolute path and vice versa.

You can also use resolve() method to create a new Path. The object on which resolve() is invoked forms the base of the new Path and the input is appended to it. Eg.

Path path1 = Paths.get("C:\\Users\\athakur\\Desktop");
Path path2 = Paths.get("abc.txt");
System.out.println(path1.resolve(path2));


Output :
C:\\Users\\athakur\\Desktop\\abc.txt

 NOTE:
  • In above example input argument was a relative path but if it is an absolute path the base is ignored and the copy of absolute argument Path is returned.
  • Like relativize() , resolve() also does not cleanup up path symbols like '..' or '.'. You can clean it up with normalize() though. Again normalize() does not check if file actually exists. That's the job for toRealPath().


Note some of the following important points
  1. Most of the methods in Path interface do not throw IOException if underlying file or directory does not exist except the method toRealPath(). That's because Path just is a representation of file in the file system not the actual file.
  2. To carry out functionality like creating/deleting directories, copying you can use methods provided in java.nio.file.Files class.
  3. toRealPath() method normalizes the path as well and converts to absolute path and returns.
  4. java.io.File class has toPath() method that return Path instance from a File instance. Similarly Path has toFile() method to get File instance.
  5. You can also get Path instance from underlying file system as -
    • FileSystems.getDefault().getPath("C:\\Users\\athakur\\Desktop") OR
    • FileSystems.getDefault().getPath("C:","Users","athakur","Desktop")
  6. Also note the Root of a file 'c:/' in above case is never counted as path element. getName(index) method will return element at position= index and position starts from 0 at element after root. So to sum up getName(int index) method is zero indexed and file systems root excluded.
  7. You can compare two paths with compareTo() method [as Path interface extends Comparable interface] or you can use equals(). compareTo() method will  compare paths character by character where as equals() will check if two paths are pointing to same file. However note for equals() to work each path should be normalized and converted to absolute path (you can use toRealPath()). Or you can simply use Files.isSameFile(path1, path2) 
  8. isSameFile() method will first check if two Paths are same irrespective of files actually exist or not. If they are same true is returned. If it returns false then the files are actually located and compared. If files does not exist then IOException is thrown. 

Below diagram summaries general way to create a Path instance.
NOTE :
  • Unlike File class Path interface contains supports for symbolic links.
  • Path is an interface. You cannot directly create a instance of Path and have to use one of the factory methods provided. This is done deliberately since files are system dependent and by using a factory method Java handles system specific details for you.
  • You can create a Path variable using a varagrg String arguments like Paths.get(String,String,...). Benefit of this is that you dont have to worry about the separator which is platform dependent. You can also get it as System.getProperty("path.separator")
  • Path object is not a file but a representation of a location within your file system. So you can perform operations like getting the root directory or parent directory without the file actually existing. However some methods like Path.toRealPath() do need file to exist and throw checked exception.
  • getRoot() method returns root element of the Path object or null of the Path is relative.
Notes :
  1. Files.isDirectory() follows links by default
  2. Files.deleteIfExists() would throw a DirectoryNotEmptyException if it had contents. It will work for empty directory or a symbolic link.
  3. Files.lines() returns a Stream<String> and Files.readAllLines() returns a List<String>. Files.lines() reads the file in a lazy manner, while Files.readAllLines() reads the entire file into memory all at once; therefore Files.lines() works better on large files with limited memory available
  4. Also see - Walking a directory using Streams API in java8 

Walking a File Tree (walkFileTree)

NOTE : Below method is for java 7. For Java 8 we have Files.walk(path) method that returns Stream<Path> which you can iterate on in a depth first pattern. See Walking a directory using Streams API in java8 

java.nio.file.Files class has two method that are provided to traverse File tree. They are - 

  • Path walkFileTree(Path start, FileVisitor<? super Path> visitor)
  • Path walkFileTree(Path start, Set<FileVisitOption> options, int maxDepth, FileVisitor<? super Path> visitor)

Both methods take instance of Path to start with and an instance of  FileVisitor that describes what action to taken when each file is visited.

FileVisitor interface provides various methods to take actions at various junctions. Methods are -

  1. visitFile()
  2. preVisitDirectory()
  3. postVisitDirectory()
  4. visitFileFailed()
You need to create a class that implements interface java.nio.file.FileVisitor . Or simply you can extends SimpleFileVisitor class and override necessary methods.

import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;


public class TestFileVisitor extends SimpleFileVisitor<Path> {
    
    public FileVisitResult visitFile(Path path, BasicFileAttributes fileAttributes) {
        System.out.println("Visiting File :" + path.getFileName());
        return FileVisitResult.CONTINUE;
    }

    public FileVisitResult preVisitDirectory(Path path, BasicFileAttributes fileAttributes) {
        System.out.println("Accessiong Directory : " + path );
        return FileVisitResult.CONTINUE;
    }
    
    public static void main(String args[])
    {
        Path startPath = Paths.get("C:\\Users\\athakur\\Desktop\\Dir1");
        System.out.println("Staring to traverse File tree");
        try {
            Files.walkFileTree(startPath, new TestFileVisitor());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


Output : 

Staring to traverse File tree
Accessiong Directory : C:\Users\athakur\Desktop\Dir1
Accessiong Directory : C:\Users\athakur\Desktop\Dir1\Dir2
Visiting File :File2 - Copy.txt
Visiting File :File2.txt
Accessiong Directory : C:\Users\athakur\Desktop\Dir1\Dir3
Visiting File :File3 - Copy.txt
Visiting File :File3.txt
Visiting File :File1 - Copy.txt
Visiting File :File1.txt

Note :
  1. You can use walkFileTree() to copy entire directory from source to destination as simple Files.copy() will just copy the directory contents not the files withing the directory of given directory [shallow copy].
  2. You can use PathMatcher to match a file. The PathMatcher interface is implemented for each file system, and you can get an instance of it from the FileSystem class using the getPathMatcher() method. Eg .

    String pattern = "glob:File*.java";
    matcher = FileSystems.getDefault().getPathMatcher(pattern);
    System.out.println(matcher.matches(path.getFileName()));

  3. Glob is a pattern-specifying mechanism where you can specify file matching patterns as strings. It's a subset of regex.
  4. postVisitDirectory() will be invoked after all files and directories of a current directory are visited including all files of it's child directories.

 Directory WatchService

By using WatchService you can watch over for changes in files corresponding to a directory. Following program checks if file is changes using WatchService -

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;


public class TestFileWatchService {

    public static void main(String args[]) throws IOException, InterruptedException {
        Path p = Paths.get("C:\\Users\\athakur\\Desktop\\Dir1");
        WatchService ws = p.getFileSystem().newWatchService();
        p.register(ws, StandardWatchEventKinds.ENTRY_MODIFY);
        
        //infinite loop
        while(true)
        {
            WatchKey watchKey = null;
            watchKey = ws.take();
            for(WatchEvent<?> event : watchKey.pollEvents()){
                switch(event.kind().name()){
                    case "OVERFLOW":
                        System.out.println("Some events were lost");
                        break;
                    case "ENTRY_MODIFY":
                        System.out.println("File " + event.context() + " is changed!");
                        break;
                }
            }
            watchKey.reset();//reset the key to get further notifications
        }
    }
    
}

Now try changing any file in the directory you should see output like - 
File File1.txt is changed!
File File1.txt is changed!
File File1.txt is changed!


Few  important points to note here :
  1. You can also create new WatchService using FileSystems.getDefault().newWatchService().
  2. take() method is a blocking call. It will wait till a WatchKey is available where as the poll() method that can also be used to get key is a non blocking call i.e it returns immediately if key is not available.
  3. Once events are polled from the key do not forget to reset the key or else you will not get subsequent event notifications.
  4. Your program may receive an OVERFLOW event even if the path is not registered with some watch service for some events.
  5. Only files in given directory are watched not the ones in subdirectories.
  6. If Path does not correspond to a directory you will get following Exception :

    Exception in thread "main" java.nio.file.NotDirectoryException: C:\Users\athakur\Desktop\abc.txt
        at sun.nio.fs.WindowsWatchService$Poller.implRegister(Unknown Source)
        at sun.nio.fs.AbstractPoller.processRequests(Unknown Source)
        at sun.nio.fs.WindowsWatchService$Poller.run(Unknown Source)
        at java.lang.Thread.run(Unknown Source)

Related Links

t> UA-39527780-1 back to top