Feb 11 2008

Reading Client-side Files with XPCOM

Recently I wrote a tutorial on how to use XPCOM in FireFox to access the user’s disk drive. With XPCOM you can access core browser functionality and with the right permissions can even read files and data off the user’s disk drive, access the network, and much more. In this code walk through we will look at how to read the contents of a file saved on the users desktop using JavaScript code from FireFox.

Before we get started we need to define XPCOM contract id and interface used to access files on the client-side. To access user files, you need to enable the correct privileges and for that you negotiate with the browser Privilege Manager.

// Id and interface for file reference
var fileContractId = "@mozilla.org/file/local;1";
var fileInterface = Components.interfaces.nsILocalFile;

// Id and interface for input stream
var inputContractId = "@mozilla.org/network/file-input-stream;1";
var inputInterface = Components.interfaces.nsIFileInputStream;

// Id and interface for scriptable input stream
var sinputContractId = "@mozilla.org/scriptableinputstream;1";
var sinputInterface = Components.interfaces.nsIScriptableInputStream;

// Request proper security privileges
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");

The XPCOM interfaces we will be using here is the local file which acts as a reference to the file. The file input stream and scriptable input stream will be used to read in the file data.

As noted in the previous XPCOM tutorial, you use the contract id and interfaces get objects that implement them. The next snippet of code will define the path of the file whose data will be read and it will crate the correct file and input file objects to do so.

// Path to file
var readFilePath = "/Users/juixe/Desktop/temp.txt";

// Get file reference
var fileClass = Components.classes[fileContractId];
var file = fileClass.createInstance(fileInterface);
file.initWithPath(readFilePath);

// Get input stream
var inputClass = Components.classes[inputContractId];
var inputStream = inputClass.createInstance(inputInterface);
inputStream.init(file,0x01,null, null);

Notice that to initialize the file input stream I passed in a file reference to the file and a few other parameters. There is some XPCOM documentation on XUL Planet descring these parameters but it is probably best to find sample code to see its usage in the field as I had some difficulty making heads or tails out the documentation.

To get access at the data in the temp file use the scriptable input stream such as the following code.

// Need scriptable input stream to get content
var sinputClass = Components.classes[sinputContractId];
var sinputStream = sinputClass.createInstance(sinputInterface);
sinputStream.init(inputStream);

// Print file data
document.write("File Data: "+sinputStream.read(sinputStream.available()));

Notice that the scriptable input stream was initialized with the input stream created earlier. To read the date in the temp file use read in as many bytes as you would like.

Once done with the input streams you can just close them.

sinputStream.close();
inputStream.close();

Feb 5 2008

VMWare Fusion – Virtualization Software

After seeing a Google tech talk on VMWare Fusion, I thought I give it a try. VMWare Fusion is a virtualization software for the Mac OS X that allows you to run additional Operating Systems such as Windows XP or Ubuntu while running Mac OS X at the same time. Basically you can run an additional guest system inside a VMWare Fusion window from Mac OS X. This differs from Boot Camp in that you can run both systems at once, not pick which to run at boot time.

After installing, VMWare Fusion immideately found Windows from my Boot Camp partition. I also found a Ubuntu 7.10 VMWare image from Ubuntu itself although you can find images on VMWare’s Virtual Marketplace.

VMWare is a awesome technology that I foresee myself using as much as possible but it does have some bugs and shortcomings. I had to reactive windows after running it from VMWare Fusion, Windows complaint about having the hardware on the computer change significantly. I also experience an annoyance that the DVD player would start to play. I also found it annoying that you have to hit ctrl+alt to return to the host computer, I wish VMWare was as seamless as Windows’ Remote Desktop Connectivity. And worst of all, WMWare Fusion costs $79, while the Windows version, VMWare Player, is free!!!

Technorati Tags: , , , , , , , ,


Jan 17 2008

Print a PDF Document in Java

For some time now I have searched for a way to print a PDF document from Java code. Up to now, I have had to shell out and invoke Acrobat from the command line but this hack has been painful to support in the field because of the multiple version of Acrobat and its quirks.

A new PDF Renderer project has recently been released on java.net which can in addition to rendering and viewing a PDF document, it can be used to print a PDF document. If you download the PDF Renderer you can run the jar to start a sample PDF viewer application which can print PDF documents. All the code listed below is inspired from the PDF Renderer sample application.

The following code uses classes from the PDF Renderer library and standard Java. Like usual, I have omitted all import statements.

// Create a PDFFile from a File reference
File f = new File("c:\\juixe\\techknow.pdf");
FileInputStream fis = new FileInputStream(f);
FileChannel fc = fis.getChannel();
ByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
PDFFile pdfFile = new PDFFile(bb); // Create PDF Print Page
PDFPrintPage pages = new PDFPrintPage(pdfFile);

// Create Print Job
PrinterJob pjob = PrinterJob.getPrinterJob();
PageFormat pf = PrinterJob.getPrinterJob().defaultPage();
pjob.setJobName(f.getName());
Book book = new Book();
book.append(pages, pf, pdfFile.getNumPages());
pjob.setPageable(book);

// Send print job to default printer
pjob.print();

One critical class required to print a PDF document using PDF Renderer is the PDFPrintPage. The PDFPrintPage implements the Printable print method. The PDFPrintPage is included in the PDFRenderer.jar, but in the source distribution it is found under the demos project. I have included the source to PDFPrintPage print method here…

class PDFPrintPage implements Printable {
  private PDFFile file;
  PDFPrintPage(PDFFile file) {
    this.file = file;
  }

  public int print(Graphics g, PageFormat format, int index) 
    throws PrinterException {
    int pagenum = index + 1;

    // don't bother if the page number is out of range.
    if ((pagenum >= 1) && (pagenum < = file.getNumPages())) {
      // fit the PDFPage into the printing area
      Graphics2D g2 = (Graphics2D)g;
      PDFPage page = file.getPage(pagenum);
      double pwidth = format.getImageableWidth();
      double pheight = format.getImageableHeight();

      double aspect = page.getAspectRatio();
      double paperaspect = pwidth / pheight;

      Rectangle imgbounds;

      if (aspect>paperaspect) {
        // paper is too tall / pdfpage is too wide
        int height= (int)(pwidth / aspect);
        imgbounds= new Rectangle(
          (int)format.getImageableX(),
          (int)(format.getImageableY() + ((pheight - height) / 2)),
          (int)pwidth,
          height
        );
      } else {
        // paper is too wide / pdfpage is too tall
        int width = (int)(pheight * aspect);
        imgbounds = new Rectangle(
          (int)(format.getImageableX() + ((pwidth - width) / 2)),
          (int)format.getImageableY(),
          width,
          (int)pheight
        );
      }

      // render the page
      PDFRenderer pgs = new PDFRenderer(page, g2, imgbounds, null, null);
      try {
        page.waitForFinish();
        pgs.run();
      } catch (InterruptedException ie) {}

      return PAGE_EXISTS;
    } else {
      return NO_SUCH_PAGE;
    }
  }
}

A final note, PDF Renderer does require Java 1.5 or greater.


Jan 14 2008

Accessing Local Files With Mozilla XPCOM

A few months back I took a look at TIBCO General Interface, an AJAX/Web Development framework with an IDE/Builder than runs on your browser. The one thing that amazed me about General Interface was that it saved files to your local disk drive from the browser.

Earlier today I was experimenting with TiddlyWiki, a wiki that is self contained in one file and noticed that it can also save files to your hard drive from the browser. TiddlyWiki is a entire wiki system written in HTML, CSS, and JavaScript and self contained in a single HTML file. When you make a wiki edit, TiddlyWiki writes and saves the change to your local disk drive. To learn more about how to go about doing this I took a peak at the page source code, which was like opening a can of gummy worms.

As you can imagine, saving a file to the local disk from the browser is not a standardized process. IE uses ActiveX controls to go about doing this, will FireFox uses XPCOM objects. In this article I will explore getting at local files from Firefox using XPCOM.

XPCOM is Mozilla’s Cross-Platform Component Object Model used in FireFox. Many of FireFox’s services and component objects, such as your bookmarks, are available from through XPCOM. XPCOM authors can create components in either JavaScript or C which can then be added onto Mozilla as an extension. FireFox by default has a large set of core XPCOM services and objects. Once these components are available in your browser you can make use of them in JavaScript. To better illustrate this we will use the local file component in Firefox to read data from your local disk.

To get a reference to a XPCOM object you need a contract ID, which is like a registry entry string identifier for the object component, and an interface for that object. The XPCOM interface is just like a Java interface in that it defines methods and can inherit from other interfaces.

var fileContractId = "@mozilla.org/file/local;1";
var fileInterface = Components.interfaces.nsILocalFile;

Some components, such as the local file need special privileges, since you wouldn’t want any web page to read and write files on your local system. To enable the privileges you need to invoke the following JavaScript code in your script which asks the end user for these privileges.

netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");

Now that we have the component contract id, interface, and the right permissions we can create a file object.

var localFileClass = Components.classes[fileContractId];
var file = localFileClass.createInstance(fileInterface);

For the most part, a local file object is just a reference to a file. The nsILocalFile interface has methods that you would expect from a file reference such as append, create, copyTo, exists, isWritable, isReadable, isDirectory, isFile. The nsILocalFile interface also has attributes such as leafName and fileSize.

Once the file object has been created you can use any of the methods defined in the interface. The first method we should use is the initWithPath which set the path to the file.

file.initWithPath('/Users/juixe/Desktop/temp.txt');

Now that the file has been created and initialized properly, we can find out the file size and if it is a file or directory with code like the following.

document.write("The file "+file.leafName+" has "+file.fileSize+" bytes of data.");
document.write("Does file exists? "+file.exists());
document.write("Is file writable?"+file.isWritable());
document.write("Is file readable?"+file.isReadable());
document.write("Is file directory?"+file.isDirectory());
document.write("Is file file?"+file.isFile());

In this article we just scratched at the surface of what you can do with XPCOM, in the next article I’ll go over the code to read and write bytes to a file using a file input/output stream. If you can’t wait ’till next time, just view the source code of TiddlyWiki….


Jan 10 2008

The Great Grails Switch

The Apple Switch Ad campaign was very successful for Apple, so much so that there seems to be a sort of switch meme campaign amongst Grails folks to try to get Ruby on Rails developers to switch to Grails. Originally this blog post presented 10 reasons to switch from Rails to Grails and now Graeme Rocher of G2One has added another ten. Here is the complete list of reasons to switch to Grails… or at least top reasons to give Grails a try…

  • GORM with hibernate/spring and jpa is much better than ActiveRecord
  • No distribution problems; runs in many production ready containers
  • Internationalization out of the box (not specifically ignored as DHH does)
  • Transactions actually work, and they include save-points.
  • Not only dynamic finders and counters, but dynamic listOrderBy
  • No green threads (although this may be fixed in Ruby 2.0, around 2010?)
  • Ability to use pessimistic locking out of the box
  • Real-live prepared statements and .withCriteria method
  • Production level test reporting with built in Mocking and Stubbing
  • Search operations are based on Lucene (with a plugin)
  • A view technology that doesn’t suck
  • Mixed source development made easy with the Groovy joint compiler (no falling back to C to solve those performance problems ;-)
  • Built in support for rich conversations with Web Flow
  • A rich plug-in system that integrates Grails with technologies Java people care about like GWT, DWR, JMS etc.
  • A buzzing and growing community with a larger traffic mailing list as opposed to a stagnating one
  • Built on Spring, the ultimate Enterprise Application Integration technology
  • A Service layer with automatic transaction demarcation and support for scopes
  • More books coming and being adopted by enterprise organizations near you

For the true die hard Ruby on Rails developers this might not be reason enough to switch to Grails, but for those Java developers on that are on the fence Grails might seem a bit more attractive now.

For those interested in getting started with Grails, take a look at my Groovy and Grails tutorials.

Technorati Tags: , , , , , ,


Jan 8 2008

Practices of an Agile Developer – Book Critique

As you may gather from the title, this book explains in detail many of the extreme and agile programming best practices. I think a more suitable name would be Common Practices of a Software Developer as I felt that some of the practices where just common sense advice for a experience developer. I mean, do you need to read two pages to understand to check in code into version control as soon as possible, as soon as you made a fix, every half day if possible but not every five minutes? Well if you do read practice 43, Share Code Only When Ready.

What I liked about this book was that each practice was introduced by a little programming devil that tried to influence the reader into ignoring the practice altogether. This little devil is the one makes us forget to comment our code, that likes to code rather than test. At the end of each practice there is a little angel that describes the benefits of incorporating the practice as a habit into your daily routine, a routine that should include stand up meetings, check out/ins, testing, continuous integration, mentoring, etc.

A book like this might be better suited for a junior developer that does not have experience with extreme programming or any other process for that matter.

Here are some pearls of common sense from Practices of an Agile Developer.

Fix the problem, not the symptom.

The best thing for developers may not be the best for users, and vice versa.

Most users would rather have good software today than wait for superior software a year later.

Having short iterations and smaller increments helps developers stay focused.

Unit testing is an investment. Invest wisely. Testing accessors or trivial methods is probably not time well spent.

Here are some common sense practices I adhered too.

There is more than one way to do it, but do it how more than one developer can understand it.

Design a software solution for the end user, not for a fellow developer, or worse yet your database.

If the end user can’t use your software, that’s a bug.

You may consider your code as art but no one is going to hang your code in the Louvre.

Eat fruit and vegetables before you program.

Technorati Tags: , , , , ,