blob: 05add928186bff24de10c9d5aee631ddd5c0859a [file] [log] [blame]
/**
* 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.xml.security.test.dom.utils;
import org.apache.xml.security.utils.WeakObjectPool;
import org.apache.xml.security.utils.XMLUtils;
import org.junit.Test;
import javax.xml.parsers.DocumentBuilder;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.util.Iterator;
import java.util.concurrent.*;
import static org.junit.Assert.*;
public class DocumentBuilderPoolingTest {
private static final String DOCUMENTBUILDERPROXY_CLASSNAME =
"org.apache.xml.security.utils.XMLUtils$DocumentBuilderProxy";
@Test
public void testEquals() throws Exception {
DocumentBuilder documentBuilder = XMLUtils.createDocumentBuilder(true);
assertEquals(documentBuilder, documentBuilder);
}
@Test
public void testGetValidatingDocumentBuilder() throws Exception {
DocumentBuilder documentBuilder = XMLUtils.createDocumentBuilder(true);
assertTrue(documentBuilder.isValidating());
}
@Test
public void testGetNonValidatingDocumentBuilder() throws Exception {
DocumentBuilder documentBuilder = XMLUtils.createDocumentBuilder(false);
assertFalse(documentBuilder.isValidating());
}
@Test
public void testGetValidatingAndAllowDocTypeDeclarationsDocumentBuilder() throws Exception {
DocumentBuilder documentBuilder = XMLUtils.createDocumentBuilder(true, false);
assertTrue(documentBuilder.isValidating());
assertEquals(documentBuilder.getClass().getName(), DOCUMENTBUILDERPROXY_CLASSNAME);
assertAllowDocTypeDeclarations(documentBuilder, false);
}
@Test
public void testGetValidatingAndDisAllowDocTypeDeclarationsDocumentBuilder() throws Exception {
DocumentBuilder documentBuilder = XMLUtils.createDocumentBuilder(true, true);
assertTrue(documentBuilder.isValidating());
assertEquals(documentBuilder.getClass().getName(), DOCUMENTBUILDERPROXY_CLASSNAME);
assertAllowDocTypeDeclarations(documentBuilder, true);
}
private void assertAllowDocTypeDeclarations(DocumentBuilder documentBuilder, boolean allow) throws Exception {
Field field = documentBuilder.getClass().getDeclaredField("disAllowDocTypeDeclarations");
field.setAccessible(true);
assertEquals(allow, field.get(documentBuilder));
}
@Test
public void testNewDocumentBuilderInstances() throws Exception {
int count = 4;
// get all possible combinations of DocumentBuilders:
DocumentBuilder[] documentBuilders = new DocumentBuilder[count];
for (int i = 0; i < count; i++) {
documentBuilders[i] = XMLUtils.createDocumentBuilder(i / 2 > 0, i % 2 == 1);
}
//test that we got always a new instance:
for (int i = 0; i < count; i++) {
for (int j = i + 1; j < count; j++) {
assertNotEquals(documentBuilders[i], documentBuilders[j]);
assertNotSame(documentBuilders[i], documentBuilders[j]);
}
}
}
@Test
public void testRepoolingTwice() throws Exception {
DocumentBuilder documentBuilder = XMLUtils.createDocumentBuilder(true);
assertTrue(XMLUtils.repoolDocumentBuilder(documentBuilder));
assertFalse("can't repool the same object twice!", XMLUtils.repoolDocumentBuilder(documentBuilder));
}
@Test(timeout = 30000)
public void testPooling() throws Exception {
int nThreads = 8;
ExecutorService exec = Executors.newFixedThreadPool(nThreads);
Future<?>[] results = new Future[nThreads];
for (int i = 0; i < nThreads - 1; i++) {
results[i] = exec.submit(new Runnable() {
@Override
public void run() {
try {
while (true) {
// retrieve some DocumentBuilders...
DocumentBuilder documentBuilders[] = new DocumentBuilder[10];
for (int j = 0; j < documentBuilders.length; j++) {
documentBuilders[j] = XMLUtils.createDocumentBuilder(false);
assertNotNull(documentBuilders[j]);
}
// ...then repool them so that another thread may pickup them again
for (int j = 0; j < documentBuilders.length; j++) {
assertTrue(XMLUtils.repoolDocumentBuilder(documentBuilders[j]));
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
});
}
// more or less mimic gc
results[nThreads - 1] = exec.submit(new Runnable() {
@Override
public void run() {
try {
final Field poolField = XMLUtils.class.getDeclaredField("pools");
poolField.setAccessible(true);
final WeakObjectPool[] weakObjectPools = (WeakObjectPool[]) poolField.get(null);
final Field availableField = WeakObjectPool.class.getDeclaredField("available");
availableField.setAccessible(true);
while (true) {
final BlockingDeque blockingDeque = (BlockingDeque) availableField.get(weakObjectPools[1]);
Iterator iterator = blockingDeque.iterator();
while (iterator.hasNext()) {
((WeakReference) iterator.next()).clear();
}
Thread.sleep(200);
}
} catch (InterruptedException e) {
return;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
});
exec.shutdown();
exec.awaitTermination(5, TimeUnit.SECONDS);
for (Future<?> f : results) {
if (!f.isDone()) {
f.cancel(false);
}
try {
assertNull(f.get(1000, TimeUnit.MILLISECONDS));
} catch (CancellationException ce) {
//expected since we did cancel it
} catch (TimeoutException e) {
fail(f + "didn't cancel after timeout?");
}
}
}
}