Thursday, January 5, 2012

Pretty Format XML in Java

I've been playing with Amazon Product Advertising API for a while. One of the pain is reading the xml response, it's all in one line and I have to scroll to find useful information. Then I began to create a xml file and copy the response string into this file, using Eclipse's auto format this xml file. It's still painful when there are a lot of request need to try. So I brought this pretty xml formatter to ease the pain. And you don't need other library more than JDK.

First of all, we need the pretty-print.xsl stylesheet to indicate the format we want to be transformed.


 
 
 
 
 
  
   
  
 



Let's transform:
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

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

public class XmlUtils {

 public static String perttyFormat(String xml) {

  // 1. remove new line and tab characters
  // since Transformer will ignore those characters in elements
  xml = xml.replaceAll("\t", "");
  xml = xml.replaceAll("\n", "");

  try {
   // 2.Parse this xml into Documnet
   DocumentBuilder documentBuilder = DocumentBuilderFactory
     .newInstance().newDocumentBuilder();
   InputStream inputStream = new ByteArrayInputStream(xml.getBytes());
   Document document = documentBuilder.parse(inputStream);

   // 3.Build Transformer
   // place pretty-print.xsl in the same package as this class
   // Note that a stylesheet is needed to make formatting reliable.
   String path = XmlUtils.class.getResource("pretty-print.xsl")
     .getPath();
   TransformerFactory transformerFactory = TransformerFactory
     .newInstance();
   Transformer transformer = transformerFactory
     .newTransformer(new StreamSource(path));
   StringWriter stringWriter = new StringWriter();
   StreamResult streamResult = new StreamResult(stringWriter);
   DOMSource domSource = new DOMSource(document);
   transformer.transform(domSource, streamResult);
   return stringWriter.toString();
  } catch (ParserConfigurationException e) {
   e.printStackTrace();
  } catch (TransformerException e) {
   e.printStackTrace();
  } catch (SAXException e) {
   e.printStackTrace();
  } catch (IOException e) {
   e.printStackTrace();
  }

  return null;
 }

}

Refrence:
http://www.chipkillmar.net/2009/03/25/pretty-print-xml-from-a-dom/

Sunday, December 18, 2011

Extracting RAR Archives in Java using JUnrar

I just found a wonderful open source RAR Archives library in Java, jUnrar. It seems this project moved from sourceforge.net and document is still on the way. There is a JUnit test project comes with the source shows how to use it. I modified it a little bit to make is simpler.

The following code will extract mytest.rar into the user home directory.

1. construct rar Archive from File
File rarFile = new File("mytest.rar");
Archive archive = new Archive(rarFile);

The extraction is working around FileHeader, which represent each entry in the rar archive. It could be file or directory.

There are two things we need to pay attention:



2. It is safe to ignore directory if you don't care about empty directory, since FileHeader will give you full path of file and Java will create directory for your file if it doesn't exist.

3. Determine file name
If the file name is unicode, you need to use getFileNameW(). But if it is not, this method will give you empty String. So we have to check

FileHeader fileHeader = archive.nextFileHeader();
  while (fileHeader != null) {

   

   //2. extract file only, ignore directory since it will be created
   // along with file
   if (!fileHeader.isDirectory()) {

// 3.determine file name
   String name;

   if (fileHeader.isUnicode()) {
    name = fileHeader.getFileNameW();

   } else {
    name = fileHeader.getFileNameString();
   }

   System.out.println("find header:" + name);
    String userHome = System.getProperty("user.home");
    String separator = System.getProperty("file.separator");
    String targetPath = userHome + separator + name;

    OutputStream stream = new FileOutputStream(new File(targetPath));
    archive.extractFile(fileHeader, stream);
    stream.close();

   }

   // go to next file
   fileHeader = archive.nextFileHeader();

  }

Monday, October 17, 2011

Simple Pagination with Lucene Search Results

It is still not very straghtforward to do search result pagination in Lucene. The simplest way is still do the same search again and populate the next group of documents.

Firstly, create a Page object to calculate start and end index for certain page number. for example, page 3's record start from 20 to 29 if we show 10 records for each page.

public class Page implements Serializable {
 
 private int currentPageNo;
 private int start;
 private int end;
 private int totalCount;
 // default size is 10
 private int pageSize = 10;

 private int pageCount;

 public Page(int currentPageNo) {
  this.currentPageNo = currentPageNo;

 }

 public int getPageCount() {
  pageCount = totalCount / this.pageSize;
  if (totalCount % this.pageSize == 0)
   return pageCount;
  else
   return pageCount + 1;

 }

 public int getStart() {
  start = (currentPageNo - 1) * this.pageSize;
  return start;
 }

 public int getEnd() {
  end = getStart() + getPageSize();
  if (this.totalCount>0 && end > this.totalCount) {
   end = totalCount;
  }
  return end;
 }

 public int getCurrentPageNo() {
  return currentPageNo;
 }

 public void setCurrentPageNo(int currentPageNo) {
  this.currentPageNo = currentPageNo;
 }

 public long getTotalCount() {
  return totalCount;
 }

 public void setTotalCount(int totalCount) {
  this.totalCount = totalCount;
 }

 public int getPageSize() {
  return pageSize;
 }

 public void setPageSize(int pageSize) {
  this.pageSize = pageSize;
 }

}

Then we just load record in this Page's range:
Query query = new MatchAllDocsQuery();

  Page page = new Page(3);
  int end = page.getEnd();

  TopDocs docs = searcher.search(query, end);

  page.setTotalCount(docs.totalHits);
  System.out
    .println(docs.totalHits + " pageCount:" + page.getPageCount());

  for (int i = page.getStart(); i < page.getEnd(); i++) {

   ScoreDoc scoredoc = docs.scoreDocs[i];
   Document doc = searcher.doc(scoredoc.doc);

   System.out.println(doc.get("title"));

  }


Sunday, August 14, 2011

Escape Pasted Text into String in Eclipse

I often copy & paste text into Java Class file when I use Eclipse, especially when writing unit testing. It bothered when the text is long, when I need to add " and /n by hand to make it legally String.

Finally, I found Eclipse is smart enough to do this escape automatically. But you need to enable it via:

Windows --> Preferences --> Java --> Editor --> Typing --> In string literals --> Escape text when pasting into string literals

as :



now you can copy&paste text in eclipse:


Tuesday, July 12, 2011

Pagination with LazyDataModel loading from Spring Service in Primefaces

DataTable component in Primefaces is very powerful and flexible. It provides LazyDataModel mechanism to load pagination data. Here is my note about how to invoke injected Spring service to load data from database.

1. Integrate Spring and JSF



 
  org.springframework.web.jsf.el.SpringBeanFacesELResolver


 


2. Inject Spring Service in JSF Bean

@ManagedBean(name = "bookBean")
@RequestScoped
public class BookBean implements Serializable {


 @ManagedProperty("#{bookService}")
 private BookService bookService;
}

3. Lazy init LazyDataModel.
private LazyDataModel lazyModel;

 public LazyDataModel getLazyModel() {
  if (lazyModel == null) {
   lazyModel = new LazyDataModel() {

    @Override
    public List load(int first, int pageSize,
      String sortField, SortOrder sortOrder,
      Map filters) {
     return bookService.findAllInRange(first, first + pageSize);
    }
   };
   lazyModel.setRowCount(bookService.count());
  }
  return lazyModel;
 }

 public void setLazyModel(LazyDataModel lazyModel) {
  this.lazyModel = lazyModel;
 }

4. JSF page

   
      
     
     
    
      
     
     
    
      
     
     
       
                    
              
    

Monday, June 20, 2011

Removing border from layout unit in PrimeFaces 3.0

jQuery UI is my favorite JavaScript widget library. I tried create JSP tag library to reuse it in my web applications. Then I switched to JSF and found the wonderful PrimeFaces implemented via jQuery UI. What a smart combination!

But, as always, we need a little hack to make it works as we want. My first hacking is to hide the border in layout unit. After examined with firebug, I found the border is produced by "ui-widget-content". Therefore we can overwrite layout unit's border. PrimeFaces changed its layout unit css class name to "ui-layout-pane-north", "ui-layout-pane-west","ui-layout-pane-east" and "ui-layout-pane-center".

Therefore, to remove header layout unit using css multiple class selectors:



Friday, June 10, 2011

Eclipse Tips for Android Development

Honestly, developing android applications in Eclipse is not as pleasure as building iOS applications in Xcode. But the complication has to be, since android is addressed ao many vendors with variety of screen sizes and other differences. I will organize some productive tips to use Eclipse in android development.

iOS application don't have to worry about different screen size, there is no layout manager.

1. Split multiple attributes each one on a single line
This is very helpful when you edit layout xml file, each attribute will be displayed in one line.