You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by ce...@apache.org on 2023/03/11 06:49:12 UTC

svn commit: r1908263 - in /poi/trunk: poi-scratchpad/src/main/java/org/apache/poi/hslf/usermodel/ poi/src/main/java/org/apache/poi/extractor/ poi/src/main/java/org/apache/poi/hssf/record/crypto/ poi/src/main/java/org/apache/poi/hssf/usermodel/ poi/src/...

Author: centic
Date: Sat Mar 11 06:49:12 2023
New Revision: 1908263

URL: http://svn.apache.org/viewvc?rev=1908263&view=rev
Log:
Bug 66521: Add a utility to clear all thread locals

Otherwise some applications may complain about left-over things,
e.g. Tomcat sometimes reports warning logs if Threads are not
cleaned up before being passed back into the global thread-pool.

Added:
    poi/trunk/poi/src/main/java/org/apache/poi/util/ThreadLocalUtil.java
    poi/trunk/poi/src/test/java/org/apache/poi/util/TestThreadLocalUtil.java
Modified:
    poi/trunk/poi-scratchpad/src/main/java/org/apache/poi/hslf/usermodel/HSLFSlideShow.java
    poi/trunk/poi/src/main/java/org/apache/poi/extractor/ExtractorFactory.java
    poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/crypto/Biff8EncryptionKey.java
    poi/trunk/poi/src/main/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java
    poi/trunk/poi/src/main/java/org/apache/poi/sl/draw/DrawFactory.java
    poi/trunk/poi/src/main/java/org/apache/poi/ss/usermodel/DateUtil.java
    poi/trunk/poi/src/main/java/org/apache/poi/util/LocaleUtil.java

Modified: poi/trunk/poi-scratchpad/src/main/java/org/apache/poi/hslf/usermodel/HSLFSlideShow.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi-scratchpad/src/main/java/org/apache/poi/hslf/usermodel/HSLFSlideShow.java?rev=1908263&r1=1908262&r2=1908263&view=diff
==============================================================================
--- poi/trunk/poi-scratchpad/src/main/java/org/apache/poi/hslf/usermodel/HSLFSlideShow.java (original)
+++ poi/trunk/poi-scratchpad/src/main/java/org/apache/poi/hslf/usermodel/HSLFSlideShow.java Sat Mar 11 06:49:12 2023
@@ -66,6 +66,7 @@ import org.apache.poi.sl.usermodel.Slide
 import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.Internal;
+import org.apache.poi.util.ThreadLocalUtil;
 import org.apache.poi.util.Units;
 
 /**
@@ -92,6 +93,10 @@ public final class HSLFSlideShow extends
         INIT, LOADED
     }
     private static final ThreadLocal<LoadSavePhase> loadSavePhase = new ThreadLocal<>();
+    static {
+        // allow to clear all thread-locals via ThreadLocalUtil
+        ThreadLocalUtil.registerCleaner(loadSavePhase::remove);
+    }
 
     // What we're based on
     private final HSLFSlideShowImpl _hslfSlideShow;

Modified: poi/trunk/poi/src/main/java/org/apache/poi/extractor/ExtractorFactory.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/extractor/ExtractorFactory.java?rev=1908263&r1=1908262&r2=1908263&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/extractor/ExtractorFactory.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/extractor/ExtractorFactory.java Sat Mar 11 06:49:12 2023
@@ -38,6 +38,7 @@ import org.apache.poi.poifs.filesystem.E
 import org.apache.poi.poifs.filesystem.FileMagic;
 import org.apache.poi.poifs.filesystem.POIFSFileSystem;
 import org.apache.poi.util.IOUtils;
+import org.apache.poi.util.ThreadLocalUtil;
 
 /**
  * Figures out the correct POIOLE2TextExtractor for your supplied
@@ -64,6 +65,10 @@ public final class ExtractorFactory {
 
     /** Should this thread prefer event based over usermodel based extractors? */
     private static final ThreadLocal<Boolean> threadPreferEventExtractors = ThreadLocal.withInitial(() -> Boolean.FALSE);
+    static {
+        // allow to clear all thread-locals via ThreadLocalUtil
+        ThreadLocalUtil.registerCleaner(threadPreferEventExtractors::remove);
+    }
 
     /** Should all threads prefer event based over usermodel based extractors? */
     private static Boolean allPreferEventExtractors;

Modified: poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/crypto/Biff8EncryptionKey.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/crypto/Biff8EncryptionKey.java?rev=1908263&r1=1908262&r2=1908263&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/crypto/Biff8EncryptionKey.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/crypto/Biff8EncryptionKey.java Sat Mar 11 06:49:12 2023
@@ -17,6 +17,7 @@
 package org.apache.poi.hssf.record.crypto;
 
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.util.ThreadLocalUtil;
 
 public final class Biff8EncryptionKey {
     /**
@@ -25,6 +26,10 @@ public final class Biff8EncryptionKey {
      * (e.g. {@link HSSFWorkbook}) that need this functionality.
      */
     private static final ThreadLocal<String> _userPasswordTLS = new ThreadLocal<>();
+    static {
+        // allow to clear all thread-locals via ThreadLocalUtil
+        ThreadLocalUtil.registerCleaner(_userPasswordTLS::remove);
+    }
 
     /**
      * Sets the BIFF8 encryption/decryption password for the current thread.

Modified: poi/trunk/poi/src/main/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java?rev=1908263&r1=1908262&r2=1908263&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java Sat Mar 11 06:49:12 2023
@@ -36,6 +36,7 @@ import org.apache.poi.ss.usermodel.Font;
 import org.apache.poi.ss.usermodel.HorizontalAlignment;
 import org.apache.poi.ss.usermodel.VerticalAlignment;
 import org.apache.poi.util.Removal;
+import org.apache.poi.util.ThreadLocalUtil;
 
 /**
  * High level representation of the style of a cell in a sheet of a workbook.
@@ -123,6 +124,14 @@ public final class HSSFCellStyle impleme
     private static final ThreadLocal<Short> lastDateFormat = ThreadLocal.withInitial(() -> Short.MIN_VALUE);
     private static final ThreadLocal<List<FormatRecord>> lastFormats = new ThreadLocal<>();
     private static final ThreadLocal<String> getDataFormatStringCache = new ThreadLocal<>();
+    static {
+        // allow to clear all thread-locals via ThreadLocalUtil
+        ThreadLocalUtil.registerCleaner(() -> {
+            lastDateFormat.remove();
+            lastFormats.remove();
+            getDataFormatStringCache.remove();
+        });
+    }
 
     /**
      * Get the contents of the format string, by looking up
@@ -637,7 +646,7 @@ public final class HSSFCellStyle impleme
         _format.setFillBackground(bg);
         checkDefaultBackgroundFills();
     }
-    
+
     /**
      * Set the background fill color represented as a {@link org.apache.poi.ss.usermodel.Color} value.
      * <br>
@@ -696,7 +705,7 @@ public final class HSSFCellStyle impleme
         _format.setFillForeground(bg);
         checkDefaultBackgroundFills();
     }
-    
+
     /**
      * Set the foreground fill color represented as a {@link org.apache.poi.ss.usermodel.Color} value.
      * <br>

Modified: poi/trunk/poi/src/main/java/org/apache/poi/sl/draw/DrawFactory.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/sl/draw/DrawFactory.java?rev=1908263&r1=1908262&r2=1908263&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/sl/draw/DrawFactory.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/sl/draw/DrawFactory.java Sat Mar 11 06:49:12 2023
@@ -38,9 +38,14 @@ import org.apache.poi.sl.usermodel.Table
 import org.apache.poi.sl.usermodel.TextBox;
 import org.apache.poi.sl.usermodel.TextParagraph;
 import org.apache.poi.sl.usermodel.TextShape;
+import org.apache.poi.util.ThreadLocalUtil;
 
 public class DrawFactory {
     private static final ThreadLocal<DrawFactory> defaultFactory = new ThreadLocal<>();
+    static {
+        // allow to clear all thread-locals via ThreadLocalUtil
+        ThreadLocalUtil.registerCleaner(defaultFactory::remove);
+    }
 
     /**
      * Set a custom draw factory for the current thread.

Modified: poi/trunk/poi/src/main/java/org/apache/poi/ss/usermodel/DateUtil.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/ss/usermodel/DateUtil.java?rev=1908263&r1=1908262&r2=1908263&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/ss/usermodel/DateUtil.java [UTF-8] (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/ss/usermodel/DateUtil.java [UTF-8] Sat Mar 11 06:49:12 2023
@@ -36,6 +36,7 @@ import java.util.regex.Pattern;
 
 import org.apache.poi.ss.formula.ConditionalFormattingEvaluator;
 import org.apache.poi.util.LocaleUtil;
+import org.apache.poi.util.ThreadLocalUtil;
 
 /**
  * Contains methods for dealing with Excel dates.
@@ -546,6 +547,14 @@ public class DateUtil {
     private static final ThreadLocal<Integer> lastFormatIndex = ThreadLocal.withInitial(() -> -1);
     private static final ThreadLocal<String> lastFormatString = new ThreadLocal<>();
     private static final ThreadLocal<Boolean> lastCachedResult = new ThreadLocal<>();
+    static {
+        // allow to clear all thread-locals via ThreadLocalUtil
+        ThreadLocalUtil.registerCleaner(() -> {
+            lastFormatIndex.remove();
+            lastFormatString.remove();
+            lastCachedResult.remove();
+        });
+    }
 
     private static boolean isCached(String formatString, int formatIndex) {
         return formatIndex == lastFormatIndex.get()

Modified: poi/trunk/poi/src/main/java/org/apache/poi/util/LocaleUtil.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/util/LocaleUtil.java?rev=1908263&r1=1908262&r2=1908263&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/util/LocaleUtil.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/util/LocaleUtil.java Sat Mar 11 06:49:12 2023
@@ -57,6 +57,13 @@ public final class LocaleUtil {
 
     private static final ThreadLocal<TimeZone> userTimeZone = new ThreadLocal<>();
     private static final ThreadLocal<Locale> userLocale = new ThreadLocal<>();
+    static {
+        // allow to clear all thread-locals via ThreadLocalUtil
+        ThreadLocalUtil.registerCleaner(() -> {
+            userTimeZone.remove();
+            userLocale.remove();
+        });
+    }
 
     /**
      * As time zone information is not stored in any format, it can be

Added: poi/trunk/poi/src/main/java/org/apache/poi/util/ThreadLocalUtil.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/util/ThreadLocalUtil.java?rev=1908263&view=auto
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/util/ThreadLocalUtil.java (added)
+++ poi/trunk/poi/src/main/java/org/apache/poi/util/ThreadLocalUtil.java Sat Mar 11 06:49:12 2023
@@ -0,0 +1,63 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+package org.apache.poi.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Small utility to allow to remove references held in ThreadLocals.
+ *
+ * This is sometimes necessary, e.g. when returning threads into a global
+ * thread pool.
+ *
+ * For each usage of ThreadLocal, a cleaner is registered via
+ * registerCleaner().
+ */
+public class ThreadLocalUtil {
+    private final static List<Runnable> registeredCleaners = new ArrayList<>();
+
+    private ThreadLocalUtil() {
+    }
+
+    /**
+     * Clear {@link ThreadLocal}s of the current thread.
+     *
+     * This can be used to clean out a thread before "returning"
+     * it to a thread-pool or a Web-Container like Tomcat.
+     *
+     * Usually org.apache.xmlbeans.ThreadLocalUtil#clearAllThreadLocals()
+     * should be called as well to clear out some more ThreadLocals which
+     * are created by the XMLBeans library internally.
+     */
+    public static void clearAllThreadLocals() {
+        // run all registered cleaners
+        registeredCleaners.forEach(Runnable::run);
+    }
+
+    /**
+     * Intended for internal use only so other modules of Apache POi
+     * can add cleaners.
+     *
+     * @param cleaner a runnable which clears some thread-local that is
+     *                located outside of the "poi" module.
+     */
+    @Internal
+    public static void registerCleaner(Runnable cleaner) {
+        registeredCleaners.add(cleaner);
+    }
+}

Added: poi/trunk/poi/src/test/java/org/apache/poi/util/TestThreadLocalUtil.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/test/java/org/apache/poi/util/TestThreadLocalUtil.java?rev=1908263&view=auto
==============================================================================
--- poi/trunk/poi/src/test/java/org/apache/poi/util/TestThreadLocalUtil.java (added)
+++ poi/trunk/poi/src/test/java/org/apache/poi/util/TestThreadLocalUtil.java Sat Mar 11 06:49:12 2023
@@ -0,0 +1,57 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+package org.apache.poi.util;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.apache.poi.sl.draw.DrawFactory;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+
+public class TestThreadLocalUtil {
+    private final MemoryLeakVerifier verifier = new MemoryLeakVerifier();
+
+    @AfterEach
+    void tearDown() {
+        verifier.assertGarbageCollected();
+    }
+
+    @Test
+    public void testClearThreadLocalsNoData() {
+        // simply calling it without any thread locals should work
+        ThreadLocalUtil.clearAllThreadLocals();
+    }
+
+    @Test
+    public void testClearThreadLocalsWithData() {
+        DrawFactory factory = new DrawFactory();
+
+        // use the memory leak verifier to ensure that the thread-local is
+        // released after the clear-call below
+        verifier.addObject(factory);
+
+        // store the object in a thread-local
+        DrawFactory.setDefaultFactory(factory);
+
+        // retrieving it works now
+        assertEquals(factory, DrawFactory.getInstance(null));
+
+        // then clear them so that the verifier in tearDown() does not
+        // see the reference any longer
+        ThreadLocalUtil.clearAllThreadLocals();
+    }
+}
\ No newline at end of file



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org