Archive for April, 2006

jxl.read.biff.BiffException: Unable to recognize OLE stream

Written by coregps on Wednesday, April 26th, 2006 in Java.

If you're new here, you may want to subscribe to my RSS feed. Thanks for visiting!

I have been using JExcelAPI to import data from excel spreadsheets to database. For ease of use, I wrote a JavaBean named DataImport. However, it can not work recently. it always gives me the following exception:

jxl.read.biff.BiffException: Unable to recognize OLE stream
 at jxl.read.biff.CompoundFile.(CompoundFile.java:116)
 at jxl.read.biff.File.(File.java:127)
 at jxl.Workbook.getWorkbook(Workbook.java:268)
 at jxl.Workbook.getWorkbook(Workbook.java:253)

I first considered the problem was caused by Excel 2003. Because we used Excel 2000 originally, which uses the BIFF8 format, while excel XP and excel 2003 use BIFF8X format which is an extension of The BIFF8 format. However, when I imported an excel file created in excel2000, I got the same exception.

I downloaded the source code of JExcelAPI, and found the code line throwing the exception

// CompoundFile.java

    // First verify the OLE identifier
    for (int i = 0; i < IDENTIFIER.length; i++)
    {
      if (data[i] != IDENTIFIER[i])
      {
        throw new BiffException(BiffException.unrecognizedOLEFile);
      }
    }

The definition of IDENTIFIER can be found in BaseCompoundFile.java

  /**
   * The identifier at the beginning of every OLE file
   */
  protected static final byte[] IDENTIFIER = new byte[]
    {(byte) 0xd0,
     (byte) 0xcf,
     (byte) 0x11,
     (byte) 0xe0,
     (byte) 0xa1,
     (byte) 0xb1,
     (byte) 0x1a,
     (byte) 0xe1};

And then, I opened the excel file using UltraEdit in Hex mode

                 0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00000000h: D0 CF 11 E0 A1 B1 1A E1 00 00 00 00 00 00 00 00 ; ?.???.......
00000010h: 00 00 00 00 00 00 00 00 3E 00 03 00 FE FF 09 00 ; ........>...?..
00000020h: 06 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 ; ................
00000030h: 01 00 00 00 00 00 00 00 00 10 00 00 02 00 00 00 ; ................
00000040h: 01 00 00 00 FE FF FF FF 00 00 00 00 00 00 00 00 ; ....?    ........

As you can see, the first 8 bytes of the file is the same as the definition in BaseCompoundFile.java. So, it is not the problem of the excel file. I compared my code with the working one carefully, and found the root cause of the problem in the end.

The excel file is uploaded using a multipart/form-data form. In the working one, there is only an input type=”file” element in the form element. It is something like this:

<form action="upload.jsp" enctype="MULTIPART/FORM-DATA" method=post>
    Select file to import <input type="file" name="excelfilename"> <br>
    <input type="submit" value="Import">
</form>

While in the one throwing the exception, there are some other elements besides the file element:

<form action="upload.jsp" enctype="MULTIPART/FORM-DATA" method=post>
Select table to import <br/>
<input type="radio" name="tbl2import" value="1">Product<br/>
<input type="radio" name="tbl2import" value="2">Order<br/>
<input type="radio" name="tbl2import" value="3">Customer<br/>
    Select file to import <input type="file" name="excelfilename"> <br>
    <input type="submit" value="Import">
</form>

And the following is the code snippet used to parse the input stream from the request.

ServletInputStream is = request.getInputStream();
byte[] junk = new byte[1024];
int bytesRead = 0;
// strip off the HTTP information from input stream
// the first four lines are request junk
bytesRead = is.readLine(junk, 0, junk.length);
bytesRead = is.readLine(junk, 0, junk.length);
bytesRead = is.readLine(junk, 0, junk.length);
bytesRead = is.readLine(junk, 0, junk.length);
// create the workbook object from the ServletInputStream
Workbook workbook = Workbook.getWorkbook(is);
Sheet sheet = workbook.getSheet(0);

When using the former form, the input stream from the request contains only the contents of the uploaded file. While using the latter one, the input stream contains not only the contents of the excel file, but also the contents of the other form elements, this is the reason why JExcelAPI throwing the “Unable to recognize OLE stream” exception.

To solve the problem, there are two solutions.

1) Remove all of the other form elements from the upload form except the file element.

2) Use the commons upload package from Jakarta  to handle the multipart/form-data POST request. And change the code used to parse the request to something like this(IMO, this is the better one.):

// Create a factory for disk-based file items
FileItemFactory factory = new DiskFileItemFactory();
// Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload(factory);
// Parse the request
List  items = upload.parseRequest(request);
InputStream is = null;
// Process the uploaded items
Iterator iter = items.iterator();
while (iter.hasNext()) {
    FileItem item = (FileItem) iter.next();
    if (!item.isFormField()) {
        is = item.getInputStream();
        break;
    }
}
// create the workbook object from the ServletInputStream
Workbook workbook = Workbook.getWorkbook(is);
Sheet sheet = workbook.getSheet(0);

The problem above gave me a lession. Most of time I know it works. but don’t understand why it works as it does. I must be serious later.

getOutputStream() has already been called for this response

Written by coregps on Monday, April 17th, 2006 in Java.

Today, When I export data from database to an excel file, I always get the following exception:

java.lang.IllegalStateException: getOutputStream() has already been called for this response
 at org.apache.catalina.connector.Response.getWriter(Response.java:596)
 at org.apache.catalina.connector.ResponseFacade.getWriter(ResponseFacade.java:186)
 at org.apache.jasper.runtime.JspWriterImpl.initOut(JspWriterImpl.java:124)
 at org.apache.jasper.runtime.JspWriterImpl.flushBuffer(JspWriterImpl.java:117)
 at org.apache.jasper.runtime.JspWriterImpl.write(JspWriterImpl.java:326)
 at org.apache.jasper.runtime.JspWriterImpl.write(JspWriterImpl.java:337)

Below is the code used to export the excel file:

<c:if test="${param.do == 'export'}">
<%
response.setHeader("Content-Disposition","attachment; filename=report.xls");
exp.setOutput(response.getOutputStream());
exp.setCategoryName(sCatetoryName.trim());
exp.setData(result);
exp.setColumnNames(new String[] {"id", "productname", "price", "inventory"});
exp.setRow(2);
exp.setFilename("product.xls");
exp.exportData();
%>
</c:if>

I’ve tried all of the solutions found on the web, but no luck. Finally, I deployed my web application to Resin, I got another exception instead.

java.lang.NullPointerException
 at com.esurfer.freshetgis.DataExport.exportData(DataExport.java:176)
 at _jsp._sjcl._duikouanzhi__jsp._jspService(_duikouanzhi__jsp.java:137)
 at com.caucho.jsp.JavaPage.service(JavaPage.java:60)
 at com.caucho.jsp.Page.pageservice(Page.java:570)

According to the exception, I’ve checked my code over and again, and found the root cause of the problem. I’ve typed the wrong field name, the field “id” should be “pid”. So when I retrieved data using map.get(”id”). The code above will throw a NullPointerException. It seems that Tomcat gives the wrong error message. If you meet such a problem, and can’t work it out by following the solutions found on the web, try another way. Do not be confused by the exception message you get.

Commons FileUpload exception when parsing the request

Written by coregps on Monday, April 17th, 2006 in Java.

When I upload an excel file using Commons FileUpload, I got the following exception:


java.lang.NoClassDefFoundError: org/apache/commons/io/output/DeferredFileOutputStream
 org.apache.commons.fileupload.disk.DiskFileItemFactory.createItem(DiskFileItemFactory.java:179)
 org.apache.commons.fileupload.FileUploadBase.createItem(FileUploadBase.java:500)
 org.apache.commons.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:367)
 org.apache.commons.fileupload.servlet.ServletFileUpload.parseRequest(ServletFileUpload.java:116)

After googling the net, I found the solution. Commons FileUpload requires commons-io library. After I download the Commons IO library and put it in /WEB-INF/lib, the problem is solved.

Silent installation of JDK and JRE

Written by coregps on Monday, April 10th, 2006 in Java.

I recently have the requirement to install JDK and JRE in silent mode. This can be done by running the JDK (or JRE) installer from the command line with additional parameters.

1. Install JDK in silent mode:

<sdk>.exe /s /v”/qn [ADDLOCAL=ToolsFeature[,DemosFeature][,SourceFeature] [INSTALLDIR=<drive>:\<install_path>] [REBOOT=Suppress]”

where
<sdk>.exe is the single executable installer for the Java 2 SDK;
ADDLOCAL, if used, is either ToolsFeature[,DemosFeature][,SourceFeature];
INSTALLDIR, if used, specifies the drive and path of the installation;
and REBOOT=Suppress, if used, indicates that if locked files are encountered the computer should not be rebooted.
If ADDLOCAL=ToolsFeature[,DemosFeature][,SourceFeature] is used,
ToolsFeature indicates the tools of the J2SDK will be installed;
DemosFeature (optional) indicates that the J2SDK demos will be installed;
SourceFeature (optional) indicates that the src.zip file including the j2sdk source will be installed.
If ADDLOCAL is not used, then all of the features will be installed.
If INSTALLDIR is not specified, the installation will go into [WindowsVolume]:Program Files\j2sdk1.5.0 (default location).

Example:

jdk.exe /s /v”/qn ADDLOCAL=ToolsFeature INSTALLDIR=d:\jdk\jdk15″

2. Install JRE in silent mode:

<jre>.exe [/L<language ID>] /s /v”/qn [ADDLOCAL=jrecore[,extra][,other_US] | ALL] [IEXPLORER=1] [MOZILLA=1] [INSTALLDIR=<drive>:\<install_path>] [REBOOT=Suppress] [JAVAUPDATE=0] [CUSTOM=1]”

where
<jre>.exe is the single executable installer for the Java Runtime Environment (JRE);
/L<language ID>, if used, sets the localized language for the installer (see language IDs);
ADDLOCAL, if used, is either jrecore[,extra][,other_US] or ALL;
IEXPLORER=1, if used, indicates that the Plug-in should be registered with the Internet Explorer browser;
MOZILLA=1 indicates that the Plug-in should be registered with Mozilla 1.1 and later and Netscape browsers (for releases prior to 5.0, see note above);
INSTALLDIR, if used, specifies the drive and path of the installation;
REBOOT=Suppress, if used, indicates that if locked files are encountered the computer should not be rebooted;
JAVAUPDATE=0, if used, indicates that the Java Update feature should be disabled (the Update tab in the Java Control Panel will not appear);
and if CUSTOM=1 is used, the user will only see the license agreement, which must be accepted, and the progress bar.
If ADDLOCAL=jrecore[,extra][,other_US] is used,
jrecore indicates the core of the JRE will be installed;
extra (optional) indicates additional Fonts, Colors, and Soundbank will be installed;
other (optional) indicates locale-specific .jar files will be installed.
If ADDLOCAL=ALL is used, then all the features will be installed.
If ADDLOCAL is not used, then only the recommended features will be installed: jrecore will be installed; extra will not be installed; other will be installed only if l10n support, other than English, is installed.
If INSTALLDIR is not specified, the installation will go into C:\Program Files\java\jre1.5.0 (default location).

Example:

jre.exe /s /v”/qn ADDLOCAL=ALL IEXPLORER=1 INSTALLDIR=D:\jdk\jre”

It should be note that the command is case sensitive and there must be no spaces in the features listed with ADDLOCAL. And the command line examples above is for Windows Offline Installation only, no space should appear between the /v and the quote (”). For more information, visit:

http://java.sun.com/j2se/1.5.0/sdksilent.html

http://java.sun.com/j2se/1.5.0/docs/guide/deployment/deployment-guide/silent.html



Site Navigation