]> source.dussan.org Git - poi.git/commitdiff
Fix for 56563 - Multithreading bug when reading 2 similar files
authorDominik Stadler <centic@apache.org>
Mon, 26 May 2014 20:03:08 +0000 (20:03 +0000)
committerDominik Stadler <centic@apache.org>
Mon, 26 May 2014 20:03:08 +0000 (20:03 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1597637 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java
src/testcases/org/apache/poi/hssf/usermodel/TestCellStyle.java
test-data/spreadsheet/56563a.xls [new file with mode: 0644]
test-data/spreadsheet/56563b.xls [new file with mode: 0644]

index 07de7baf0f71e75240db13afbb68021c1bd6ce66..de18107683c1a0689a4c578b78ff0f66ba761b6c 100644 (file)
@@ -101,30 +101,36 @@ public final class HSSFCellStyle implements CellStyle {
         return _format.getFormatIndex();
     }
 
+    // we keep the cached data in ThreadLocal members in order to
+    // avoid multi-threading issues when different workbooks are accessed in 
+    // multiple threads at the same time
+    private static ThreadLocal<Short> lastDateFormat = new ThreadLocal<Short>() {
+        protected Short initialValue() {
+            return Short.MIN_VALUE;
+        }
+    };
+    private static ThreadLocal<List<FormatRecord>> lastFormats = new ThreadLocal<List<FormatRecord>>();
+    private static ThreadLocal<String> getDataFormatStringCache = new ThreadLocal<String>();
+
     /**
      * Get the contents of the format string, by looking up
      *  the DataFormat against the bound workbook
      * @see org.apache.poi.hssf.usermodel.HSSFDataFormat
      * @return the format string or "General" if not found
      */
-     
-    private static short lastDateFormat = Short.MIN_VALUE;
-    private static List<FormatRecord> lastFormats = null;
-    private static String getDataFormatStringCache = null;
-    
     public String getDataFormatString() {
-        if (getDataFormatStringCache != null) {
-            if (lastDateFormat == getDataFormat() && _workbook.getFormats().equals(lastFormats)) {
-                return getDataFormatStringCache;
+        if (getDataFormatStringCache.get() != null) {
+            if (lastDateFormat.get() == getDataFormat() && _workbook.getFormats().equals(lastFormats.get())) {
+                return getDataFormatStringCache.get();
             }
         }
 
-        lastFormats = _workbook.getFormats();
-        lastDateFormat = getDataFormat();
+        lastFormats.set(_workbook.getFormats());
+        lastDateFormat.set(getDataFormat());
 
-        getDataFormatStringCache = getDataFormatString(_workbook);
+        getDataFormatStringCache.set(getDataFormatString(_workbook));
 
-        return getDataFormatStringCache;
+        return getDataFormatStringCache.get();
     }
 
     /**
@@ -862,9 +868,9 @@ public final class HSSFCellStyle implements CellStyle {
        // Handle matching things if we cross workbooks
        if(_workbook != source._workbook) {
 
-            lastDateFormat = Short.MIN_VALUE;
-            lastFormats = null;
-            getDataFormatStringCache = null;
+            lastDateFormat.set(Short.MIN_VALUE);
+            lastFormats.set(null);
+            getDataFormatStringCache.set(null);
           
                        // Then we need to clone the format string,
                        //  and update the format record for this
index e57191b6469e1da29fb7f0f17a477fe4b2f32baf..bd874629f8d3715dfb9d430e83eafaccdfc6ee42 100644 (file)
@@ -26,7 +26,11 @@ import java.util.Date;
 import junit.framework.TestCase;
 
 import org.apache.poi.hssf.HSSFTestDataSamples;
+import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
 import org.apache.poi.util.TempFile;
 
 /**
@@ -405,4 +409,62 @@ public final class TestCellStyle extends TestCase {
        assertEquals(false, r.getCell(0).getCellStyle().getShrinkToFit());
        assertEquals(true,  r.getCell(1).getCellStyle().getShrinkToFit());
     }
+    
+    
+    
+    private static class CellFormatBugExample extends Thread {
+        private String fileName;
+        private Throwable exception = null;
+
+        public CellFormatBugExample(String fileName) {
+            this.fileName = fileName;
+        }
+
+        @Override
+        public void run() {
+            try {
+                for(int i = 0;i< 10;i++) {
+                    Workbook wb = HSSFTestDataSamples.openSampleWorkbook(fileName);
+                    Sheet sheet = wb.getSheetAt(0);
+        
+                    for (Row row : sheet) {
+                        for (Integer idxCell = 0; idxCell < row.getLastCellNum(); idxCell++) {
+        
+                            Cell cell = row.getCell(idxCell);
+                            cell.getCellStyle().getDataFormatString();
+                            if (cell.getCellType() == HSSFCell.CELL_TYPE_NUMERIC) {
+                                boolean isDate = HSSFDateUtil.isCellDateFormatted(cell);
+                                if (idxCell > 0 && isDate) {
+                                    fail("cell " + idxCell + " is not a date: " + idxCell.toString());
+                                }
+                            }
+                        }
+                    }
+                }
+            } catch (Throwable e) {
+                exception = e;
+            }
+        }
+
+        public Throwable getException() {
+            return exception;
+        }
+    };
+    
+    public void test56563() throws Throwable {
+        CellFormatBugExample threadA = new CellFormatBugExample("56563a.xls");
+        threadA.start();
+        CellFormatBugExample threadB = new CellFormatBugExample("56563b.xls");
+        threadB.start();
+        
+        threadA.join();
+        threadB.join();
+        
+        if(threadA.getException() != null) {
+            throw threadA.getException();
+        }
+        if(threadB.getException() != null) {
+            throw threadB.getException();
+        }
+    }
 }
diff --git a/test-data/spreadsheet/56563a.xls b/test-data/spreadsheet/56563a.xls
new file mode 100644 (file)
index 0000000..7fb4aa4
Binary files /dev/null and b/test-data/spreadsheet/56563a.xls differ
diff --git a/test-data/spreadsheet/56563b.xls b/test-data/spreadsheet/56563b.xls
new file mode 100644 (file)
index 0000000..7fb4aa4
Binary files /dev/null and b/test-data/spreadsheet/56563b.xls differ