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. git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1908263 13f79535-47bb-0310-9956-ffa450edef68tags/REL_5_2_4
@@ -66,6 +66,7 @@ import org.apache.poi.sl.usermodel.SlideShow; | |||
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 POIDocument implements SlideShow<HSLFSh | |||
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; |
@@ -38,6 +38,7 @@ import org.apache.poi.poifs.filesystem.Entry; | |||
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; |
@@ -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. |
@@ -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 implements CellStyle, Duplicatable { | |||
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 implements CellStyle, Duplicatable { | |||
_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 implements CellStyle, Duplicatable { | |||
_format.setFillForeground(bg); | |||
checkDefaultBackgroundFills(); | |||
} | |||
/** | |||
* Set the foreground fill color represented as a {@link org.apache.poi.ss.usermodel.Color} value. | |||
* <br> |
@@ -38,9 +38,14 @@ import org.apache.poi.sl.usermodel.TableShape; | |||
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. |
@@ -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() |
@@ -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 |
@@ -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); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |