Skip to content

Commit 933fae9

Browse files
authored
TIKA-4393 (#2163)
1 parent 2a63bc5 commit 933fae9

File tree

3 files changed

+57
-13
lines changed

3 files changed

+57
-13
lines changed

CHANGES.txt

+4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ Release 4.0.0-BETA1 - ???
44
* Headers are no longer injected into the body/content of MSG files (TIKA-4345). Please open
55
a ticket if you need this behavior across email formats.
66

7+
OTHER CHANGES
8+
9+
* Fix concurrency bug in TikaToXMP (TIKA-4393)
10+
711

812
Release 3.1.0 - ??
913

tika-xmp/src/main/java/org/apache/tika/xmp/convert/TikaToXMP.java

+9-13
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,13 @@
3636

3737
public class TikaToXMP {
3838
/**
39-
* Map from mimetype to converter class Must only be accessed through
40-
* <code>getConverterMap</code>
39+
* Map from mimetype to converter class
4140
*/
42-
private static Map<MediaType, Class<? extends ITikaToXMPConverter>> converterMap;
41+
private static final Map<MediaType, Class<? extends ITikaToXMPConverter>> CONVERTER_MAP = new HashMap<>();
42+
43+
static {
44+
initialize();
45+
}
4346

4447
// --- public API implementation---
4548

@@ -114,7 +117,7 @@ public static boolean isConverterAvailable(String mimetype) {
114117
MediaType type = MediaType.parse(mimetype);
115118

116119
if (type != null) {
117-
return (getConverterMap().get(type) != null);
120+
return (CONVERTER_MAP.get(type) != null);
118121
}
119122

120123
return false;
@@ -137,7 +140,7 @@ public static ITikaToXMPConverter getConverter(String mimetype) throws TikaExcep
137140
MediaType type = MediaType.parse(mimetype);
138141

139142
if (type != null) {
140-
Class<? extends ITikaToXMPConverter> clazz = getConverterMap().get(type);
143+
Class<? extends ITikaToXMPConverter> clazz = CONVERTER_MAP.get(type);
141144
if (clazz != null) {
142145
try {
143146
converter = clazz.getDeclaredConstructor().newInstance();
@@ -154,13 +157,6 @@ public static ITikaToXMPConverter getConverter(String mimetype) throws TikaExcep
154157

155158
// --- Private methods ---
156159

157-
private static Map<MediaType, Class<? extends ITikaToXMPConverter>> getConverterMap() {
158-
if (converterMap == null) {
159-
converterMap = new HashMap<>();
160-
initialize();
161-
}
162-
return converterMap;
163-
}
164160

165161
/**
166162
* Initializes the map with supported converters.
@@ -187,7 +183,7 @@ private static void initialize() {
187183
private static void addConverter(Set<MediaType> supportedTypes,
188184
Class<? extends ITikaToXMPConverter> converter) {
189185
for (MediaType type : supportedTypes) {
190-
getConverterMap().put(type, converter);
186+
CONVERTER_MAP.put(type, converter);
191187
}
192188
}
193189
}

tika-xmp/src/test/java/org/apache/tika/xmp/TikaToXMPTest.java

+44
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@
2323
import static org.junit.jupiter.api.Assertions.assertThrows;
2424
import static org.junit.jupiter.api.Assertions.assertTrue;
2525

26+
import java.util.concurrent.Callable;
27+
import java.util.concurrent.ExecutorCompletionService;
28+
import java.util.concurrent.ExecutorService;
29+
import java.util.concurrent.Executors;
30+
import java.util.concurrent.Future;
31+
import java.util.concurrent.TimeUnit;
32+
import java.util.concurrent.TimeoutException;
33+
2634
import com.adobe.internal.xmp.XMPConst;
2735
import com.adobe.internal.xmp.XMPException;
2836
import com.adobe.internal.xmp.XMPIterator;
@@ -225,4 +233,40 @@ public void getConverter_nullInput_throw() throws TikaException {
225233
TikaToXMP.getConverter(null);
226234
});
227235
}
236+
237+
@Test
238+
public void testMultithreaded() throws Exception {
239+
int numThreads = 10;
240+
final int numIterations = 100;
241+
ExecutorService executorService = Executors.newFixedThreadPool(numThreads);
242+
try {
243+
ExecutorCompletionService<Integer> executorCompletionService = new ExecutorCompletionService<>(executorService);
244+
for (int i = 0; i < numThreads; i++) {
245+
executorCompletionService.submit(new Callable<Integer>() {
246+
@Override
247+
public Integer call() throws Exception {
248+
for (int j = 0; j < numIterations; j++) {
249+
Metadata m = new Metadata();
250+
setupOOXMLMetadata(m);
251+
m.set(Metadata.CONTENT_TYPE, OOXML_MIMETYPE);
252+
XMPMeta xmp = TikaToXMP.convert(m);
253+
checkOOXMLMetadata(xmp);
254+
}
255+
return 1;
256+
}
257+
});
258+
}
259+
int finished = 0;
260+
while (finished < numThreads) {
261+
Future<Integer> future = executorCompletionService.poll(1, TimeUnit.MINUTES);
262+
if (future == null) {
263+
throw new TimeoutException();
264+
}
265+
future.get();
266+
finished++;
267+
}
268+
} finally {
269+
executorService.shutdownNow();
270+
}
271+
}
228272
}

0 commit comments

Comments
 (0)