Author: msahyoun Date: Tue Sep 14 19:35:02 2021 New Revision: 1893341 URL: http://svn.apache.org/viewvc?rev=1893341&view=rev Log: PDFBOX-5263: fix for ConcurrentModificationException; fix for method as suggested by Christian Appl
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSBase.java pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSUpdateInfoObserver.java pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/cos/TestCOSUpdateInfoObserver.java Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSBase.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSBase.java?rev=1893341&r1=1893340&r2=1893341&view=diff ============================================================================== --- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSBase.java (original) +++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSBase.java Tue Sep 14 19:35:02 2021 @@ -22,8 +22,8 @@ import org.apache.pdfbox.cos.observer.CO import org.apache.pdfbox.pdmodel.common.COSObjectable; import java.io.IOException; -import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; /** * The base object that all objects in the PDF document will extend. @@ -33,7 +33,7 @@ import java.util.List; public abstract class COSBase implements COSObjectable { - private final List<COSObserver> cosChangeObservers = new ArrayList<>(); + private final List<COSObserver> cosChangeObservers = new CopyOnWriteArrayList<>(); private boolean direct; private COSObjectKey key; Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSUpdateInfoObserver.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSUpdateInfoObserver.java?rev=1893341&r1=1893340&r2=1893341&view=diff ============================================================================== --- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSUpdateInfoObserver.java (original) +++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSUpdateInfoObserver.java Tue Sep 14 19:35:02 2021 @@ -21,6 +21,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import org.apache.pdfbox.cos.observer.COSIncrementObserver; import org.apache.pdfbox.cos.observer.COSObserver; @@ -69,7 +70,7 @@ public class COSUpdateInfoObserver imple /** * A map mapping monitored {@link COSUpdateInfo} to a list of structures, that hold a reference to said object. */ - private final Map<COSUpdateInfo, List<COSUpdateInfo>> referenceHolders = new HashMap<>(); + private final Map<COSUpdateInfo, List<COSUpdateInfo>> referenceHolders = new ConcurrentHashMap<>(); /** * Instantiates a new {@link COSUpdateInfoObserver} for the given {@link COSDocument}. @@ -425,12 +426,14 @@ public class COSUpdateInfoObserver imple /** * <p> * Remove the given {@link COSUpdateInfo} as a referenceHolder for the given {@link COSBase}.<br> - * If the reference holder had been the last referenceHolder of that object, remove the object from the increment - * and monitored objects all together. + * If the reference holder had been the last referenceHolder of that object, remove the object + * from the increment and monitored objects all together. * </p> * - * @param referencedObject The {@link COSBase}, that shall no longer be included in the given reference holder. - * @param previousReferenceHolder The {@link COSUpdateInfo} reference holder, that shall no longer include the object. + * @param referencedObject The {@link COSBase}, that shall no longer be included + * in the given reference holder. + * @param previousReferenceHolder The {@link COSUpdateInfo} reference holder, that shall no + * longer include the object. */ private void removeReferenceHolder(COSBase referencedObject, COSUpdateInfo previousReferenceHolder) { @@ -451,7 +454,7 @@ public class COSUpdateInfoObserver imple else { List<COSUpdateInfo> actualReferenceHolders = referenceHolders.get((COSUpdateInfo) referencedObject); - actualReferenceHolders.remove((COSUpdateInfo) referencedObject); + actualReferenceHolders.remove(previousReferenceHolder); // The object is no longer referenced and must not be part of the increment, // it shall no longer be monitored. Modified: pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/cos/TestCOSUpdateInfoObserver.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/cos/TestCOSUpdateInfoObserver.java?rev=1893341&r1=1893340&r2=1893341&view=diff ============================================================================== --- pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/cos/TestCOSUpdateInfoObserver.java (original) +++ pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/cos/TestCOSUpdateInfoObserver.java Tue Sep 14 19:35:02 2021 @@ -43,6 +43,7 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.net.URL; +import java.util.ConcurrentModificationException; public class TestCOSUpdateInfoObserver { @@ -52,7 +53,7 @@ public class TestCOSUpdateInfoObserver * Create a document from scratch - incrementally making changes - checking results of previous steps. */ @Test - public void testIncrementallyCreateDocument() + void testIncrementallyCreateDocument() { byte[] documentData = new byte[0]; @@ -244,6 +245,34 @@ public class TestCOSUpdateInfoObserver }*/ } + /** + * PDFBOX-5263: There was a ConcurrentModificationException with + * YTW2VWJQTDAE67PGJT6GS7QSKW3GNUQR.pdf - test that this issues has been resolved. + * + * @throws IOException + */ + @Test + void testConcurrentModification() throws IOException + { + URL pdfLocation = + new URL("https://issues.apache.org/jira/secure/attachment/12891316/YTW2VWJQTDAE67PGJT6GS7QSKW3GNUQR.pdf"); + + try (PDDocument document = Loader.loadPDF(pdfLocation.openStream())) + { + document.setAllSecurityToBeRemoved(true); + try + { + document.save(new ByteArrayOutputStream()); + } + catch (ConcurrentModificationException e) + { + fail("There shouldn't be a ConcurrentModificationException", e.getCause()); + } + } + } + + + private PDDocument loadDocument(byte[] documentData) { return assertDoesNotThrow(() -> Loader.loadPDF(documentData), "Loading the document failed."); }