Skip to content

Commit c715df2

Browse files
author
Eugene Bochilo
committed
Introduce way to pass MetaInfo to forms module
DEVSIX-6328
1 parent 8b4d0ca commit c715df2

File tree

6 files changed

+200
-5
lines changed

6 files changed

+200
-5
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.itextpdf.commons.utils;
2+
3+
/**
4+
* Functional interface which takes 0 parameters and returns nothing.
5+
*/
6+
@FunctionalInterface
7+
public interface Action {
8+
/**
9+
* Execute action.
10+
*/
11+
void execute();
12+
}

forms/src/main/java/com/itextpdf/forms/PdfAcroForm.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ This file is part of the iText (R) project.
8787
*/
8888
public class PdfAcroForm extends PdfObjectWrapper<PdfDictionary> {
8989

90+
private static final Logger LOGGER = LoggerFactory.getLogger(PdfAcroForm.class);
91+
9092
/**
9193
* To be used with {@link #setSignatureFlags}.
9294
* <br>
@@ -137,7 +139,6 @@ public class PdfAcroForm extends PdfObjectWrapper<PdfDictionary> {
137139
private PdfDictionary defaultResources;
138140
private Set<PdfFormField> fieldsForFlattening = new LinkedHashSet<>();
139141
private XfaForm xfaForm;
140-
private static Logger logger = LoggerFactory.getLogger(PdfAcroForm.class);
141142

142143
/**
143144
* Creates a PdfAcroForm as a wrapper of a dictionary.
@@ -720,7 +721,7 @@ public void flattenFields() {
720721
}
721722
}
722723
} else {
723-
logger.error(IoLogMessageConstant.N_ENTRY_IS_REQUIRED_FOR_APPEARANCE_DICTIONARY);
724+
LOGGER.error(IoLogMessageConstant.N_ENTRY_IS_REQUIRED_FOR_APPEARANCE_DICTIONARY);
724725
}
725726

726727
PdfArray fFields = getFields();
@@ -861,7 +862,7 @@ public void replaceField(String name, PdfFormField field) {
861862
protected PdfArray getFields() {
862863
PdfArray fields = getPdfObject().getAsArray(PdfName.Fields);
863864
if (fields == null) {
864-
logger.warn(IoLogMessageConstant.NO_FIELDS_IN_ACROFORM);
865+
LOGGER.warn(IoLogMessageConstant.NO_FIELDS_IN_ACROFORM);
865866
fields = new PdfArray();
866867
getPdfObject().put(PdfName.Fields, fields);
867868
}
@@ -877,12 +878,12 @@ private Map<String, PdfFormField> iterateFields(PdfArray array, Map<String, PdfF
877878
int index = 1;
878879
for (PdfObject field : array) {
879880
if (field.isFlushed()) {
880-
logger.info(IoLogMessageConstant.FORM_FIELD_WAS_FLUSHED);
881+
LOGGER.info(IoLogMessageConstant.FORM_FIELD_WAS_FLUSHED);
881882
continue;
882883
}
883884
PdfFormField formField = PdfFormField.makeFormField(field, document);
884885
if (formField == null) {
885-
logger.warn(MessageFormatUtil.format(IoLogMessageConstant.CANNOT_CREATE_FORMFIELD,
886+
LOGGER.warn(MessageFormatUtil.format(IoLogMessageConstant.CANNOT_CREATE_FORMFIELD,
886887
field.getIndirectReference() == null ? field : field.getIndirectReference()));
887888
continue;
888889
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package com.itextpdf.forms.fields;
2+
3+
import com.itextpdf.commons.utils.Action;
4+
import com.itextpdf.layout.renderer.MetaInfoContainer;
5+
6+
/**
7+
* Class to store meta info that will be used in forms module in static context.
8+
*/
9+
public final class FormsMetaInfoStaticContainer {
10+
11+
private static ThreadLocal<MetaInfoContainer> metaInfoForLayout = new ThreadLocal<>();
12+
13+
private FormsMetaInfoStaticContainer() {
14+
// Empty constructor.
15+
}
16+
17+
/**
18+
* Sets meta info related to forms into static context, executes the action and then cleans meta info.
19+
*
20+
* <p>
21+
* Keep in mind that this instance will only be accessible from the same thread.
22+
*
23+
* @param metaInfoContainer instance to be set.
24+
* @param action action which will be executed while meta info is set to static context.
25+
*/
26+
// TODO DEVSIX-6368 We want to prevent customer code being run while meta info is in the static context
27+
public static void useMetaInfoDuringTheAction(MetaInfoContainer metaInfoContainer, Action action) {
28+
try {
29+
metaInfoForLayout.set(metaInfoContainer);
30+
action.execute();
31+
} finally {
32+
metaInfoForLayout.set(null);
33+
}
34+
}
35+
36+
/**
37+
* Gets meta info which was set previously.
38+
*
39+
* <p>
40+
* Keep in mind that this operation will return meta info instance which was set previously from the same thread.
41+
*
42+
* @return meta info instance.
43+
*/
44+
static MetaInfoContainer getMetaInfoForLayout() {
45+
return metaInfoForLayout.get();
46+
}
47+
}

forms/src/main/java/com/itextpdf/forms/fields/PdfFormField.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ This file is part of the iText (R) project.
106106
import com.itextpdf.layout.properties.TransparentColor;
107107
import com.itextpdf.layout.properties.VerticalAlignment;
108108
import com.itextpdf.layout.renderer.IRenderer;
109+
import com.itextpdf.layout.renderer.MetaInfoContainer;
109110

110111
import java.io.ByteArrayOutputStream;
111112
import java.io.IOException;
@@ -117,6 +118,7 @@ This file is part of the iText (R) project.
117118
import java.util.List;
118119
import java.util.Map;
119120
import java.util.Set;
121+
120122
import org.slf4j.Logger;
121123
import org.slf4j.LoggerFactory;
122124

@@ -2432,6 +2434,8 @@ protected void drawTextAppearance(Rectangle rect, PdfFont font, float fontSize,
24322434
Canvas modelCanvas = new Canvas(canvas, new Rectangle(0, -height, 0, 2 * height));
24332435
modelCanvas.setProperty(Property.APPEARANCE_STREAM_LAYOUT, true);
24342436

2437+
setMetaInfoToCanvas(modelCanvas);
2438+
24352439
Style paragraphStyle = new Style().setFont(font).setFontSize(fontSize);
24362440
paragraphStyle.setProperty(Property.LEADING, new Leading(Leading.MULTIPLIED, 1));
24372441
if (color != null)
@@ -2489,6 +2493,8 @@ protected void drawMultiLineTextAppearance(Rectangle rect, PdfFont font, String
24892493
Canvas modelCanvas = new Canvas(canvas, areaRect);
24902494
modelCanvas.setProperty(Property.APPEARANCE_STREAM_LAYOUT, true);
24912495

2496+
setMetaInfoToCanvas(modelCanvas);
2497+
24922498
Paragraph paragraph = createParagraphForTextFieldValue(value).setFont(font)
24932499
.setMargin(0)
24942500
.setPadding(3)
@@ -2545,6 +2551,9 @@ private void drawChoiceAppearance(Rectangle rect, float fontSize, String value,
25452551

25462552
Canvas modelCanvas = new Canvas(canvas, new Rectangle(3, 0, Math.max(0, width - widthBorder), Math.max(0, height - heightBorder)));
25472553
modelCanvas.setProperty(Property.APPEARANCE_STREAM_LAYOUT, true);
2554+
2555+
setMetaInfoToCanvas(modelCanvas);
2556+
25482557
Div div = new Div();
25492558
if(getFieldFlag(PdfChoiceFormField.FF_COMBO)) {
25502559
div.setVerticalAlignment(VerticalAlignment.MIDDLE);
@@ -2865,6 +2874,9 @@ protected void drawButton(PdfCanvas canvas, float x, float y, float width, float
28652874
setVerticalAlignment(VerticalAlignment.MIDDLE);
28662875
Canvas modelCanvas = new Canvas(canvas, new Rectangle(0, -height, width, 2 * height));
28672876
modelCanvas.setProperty(Property.APPEARANCE_STREAM_LAYOUT, true);
2877+
2878+
setMetaInfoToCanvas(modelCanvas);
2879+
28682880
modelCanvas.showTextAligned(paragraph, width / 2, height / 2, TextAlignment.CENTER, VerticalAlignment.MIDDLE);
28692881
}
28702882

@@ -2922,6 +2934,13 @@ protected void drawPdfACheckBox(PdfCanvas canvas, float width, float height, boo
29222934
}
29232935
}
29242936

2937+
static void setMetaInfoToCanvas(Canvas canvas) {
2938+
MetaInfoContainer metaInfo = FormsMetaInfoStaticContainer.getMetaInfoForLayout();
2939+
if (metaInfo != null) {
2940+
canvas.setProperty(Property.META_INFO, metaInfo);
2941+
}
2942+
}
2943+
29252944
private String getRadioButtonValue() {
29262945
for (String state : getAppearanceStates()) {
29272946
if (!"Off".equals(state)) {
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package com.itextpdf.forms.fields;
2+
3+
import com.itextpdf.commons.actions.contexts.IMetaInfo;
4+
import com.itextpdf.layout.renderer.MetaInfoContainer;
5+
import com.itextpdf.test.ExtendedITextTest;
6+
import com.itextpdf.test.annotations.type.UnitTest;
7+
import org.junit.Assert;
8+
import org.junit.Test;
9+
import org.junit.experimental.categories.Category;
10+
11+
@Category(UnitTest.class)
12+
public class FormsMetaInfoStaticContainerTest extends ExtendedITextTest {
13+
14+
@Test
15+
public void useMetaInfoDuringTheActionOneThreadTest() {
16+
MetaInfoContainer metaInfo1 = new MetaInfoContainer(new IMetaInfo() {});
17+
MetaInfoContainer metaInfo2 = new MetaInfoContainer(new IMetaInfo() {});
18+
19+
FormsMetaInfoStaticContainer.useMetaInfoDuringTheAction(metaInfo1, () -> {
20+
Assert.assertSame(metaInfo1, FormsMetaInfoStaticContainer.getMetaInfoForLayout());
21+
22+
FormsMetaInfoStaticContainer.useMetaInfoDuringTheAction(metaInfo2,
23+
() -> Assert.assertSame(metaInfo2, FormsMetaInfoStaticContainer.getMetaInfoForLayout()));
24+
25+
Assert.assertNull(FormsMetaInfoStaticContainer.getMetaInfoForLayout());
26+
});
27+
28+
Assert.assertNull(FormsMetaInfoStaticContainer.getMetaInfoForLayout());
29+
}
30+
31+
@Test
32+
public void useMetaInfoDuringTheActionSeveralThreadsTest() throws InterruptedException {
33+
MetaInfoCheckClass metaInfoCheckClass1 = new MetaInfoCheckClass(null);
34+
MetaInfoCheckClass metaInfoCheckClass2 = new MetaInfoCheckClass(metaInfoCheckClass1);
35+
MetaInfoCheckClass metaInfoCheckClass3 = new MetaInfoCheckClass(metaInfoCheckClass2);
36+
37+
Thread thread = new Thread(() -> metaInfoCheckClass3.checkMetaInfo());
38+
thread.start();
39+
thread.join();
40+
41+
Assert.assertFalse(metaInfoCheckClass1.isCheckFailed());
42+
Assert.assertFalse(metaInfoCheckClass2.isCheckFailed());
43+
Assert.assertFalse(metaInfoCheckClass3.isCheckFailed());
44+
}
45+
46+
private static class MetaInfoCheckClass {
47+
48+
private MetaInfoCheckClass metaInfoCheckClass = null;
49+
private boolean checkFailed = false;
50+
51+
public MetaInfoCheckClass(MetaInfoCheckClass metaInfoCheckClass) {
52+
this.metaInfoCheckClass = metaInfoCheckClass;
53+
}
54+
55+
public void checkMetaInfo() {
56+
MetaInfoContainer metaInfo = new MetaInfoContainer(new IMetaInfo() {
57+
});
58+
59+
FormsMetaInfoStaticContainer.useMetaInfoDuringTheAction(metaInfo, () -> {
60+
if (metaInfoCheckClass != null) {
61+
Thread thread = new Thread(() -> metaInfoCheckClass.checkMetaInfo());
62+
thread.start();
63+
try {
64+
thread.join();
65+
} catch (Exception ignored) {
66+
checkFailed = true;
67+
}
68+
}
69+
70+
checkFailed |= metaInfo != FormsMetaInfoStaticContainer.getMetaInfoForLayout();
71+
});
72+
73+
checkFailed |= FormsMetaInfoStaticContainer.getMetaInfoForLayout() != null;
74+
}
75+
76+
public boolean isCheckFailed() {
77+
return checkFailed;
78+
}
79+
}
80+
}

forms/src/test/java/com/itextpdf/forms/fields/PdfFormFieldUnitTest.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,20 @@ This file is part of the iText (R) project.
2222
*/
2323
package com.itextpdf.forms.fields;
2424

25+
import com.itextpdf.commons.actions.contexts.IMetaInfo;
2526
import com.itextpdf.forms.exceptions.FormsExceptionMessageConstant;
2627
import com.itextpdf.io.source.ByteArrayOutputStream;
2728
import com.itextpdf.kernel.exceptions.PdfException;
29+
import com.itextpdf.kernel.geom.Rectangle;
2830
import com.itextpdf.kernel.pdf.PdfDictionary;
2931
import com.itextpdf.kernel.pdf.PdfDocument;
32+
import com.itextpdf.kernel.pdf.PdfResources;
33+
import com.itextpdf.kernel.pdf.PdfStream;
3034
import com.itextpdf.kernel.pdf.PdfWriter;
35+
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
36+
import com.itextpdf.layout.Canvas;
37+
import com.itextpdf.layout.properties.Property;
38+
import com.itextpdf.layout.renderer.MetaInfoContainer;
3139
import com.itextpdf.test.ExtendedITextTest;
3240
import com.itextpdf.test.annotations.type.UnitTest;
3341

@@ -47,4 +55,32 @@ public void cannotGetRectangleIfKidsIsNullTest() {
4755
() -> pdfFormField.getRect(pdfDictionary));
4856
Assert.assertEquals(FormsExceptionMessageConstant.WRONG_FORM_FIELD_ADD_ANNOTATION_TO_THE_FIELD, exception.getMessage());
4957
}
58+
59+
@Test
60+
public void setMetaInfoToCanvasMetaInfoUsedTest() {
61+
Canvas canvas = createCanvas();
62+
MetaInfoContainer metaInfoContainer = new MetaInfoContainer(new IMetaInfo() {
63+
});
64+
FormsMetaInfoStaticContainer.useMetaInfoDuringTheAction(metaInfoContainer,
65+
() -> PdfFormField.setMetaInfoToCanvas(canvas));
66+
67+
Assert.assertSame(metaInfoContainer, canvas.<MetaInfoContainer>getProperty(Property.META_INFO));
68+
}
69+
70+
@Test
71+
public void setMetaInfoToCanvasMetaInfoNotUsedTest() {
72+
Canvas canvas = createCanvas();
73+
PdfFormField.setMetaInfoToCanvas(canvas);
74+
75+
Assert.assertNull(canvas.<MetaInfoContainer>getProperty(Property.META_INFO));
76+
}
77+
78+
private static Canvas createCanvas() {
79+
try (PdfDocument document = new PdfDocument(new PdfWriter(new ByteArrayOutputStream()))) {
80+
PdfStream stream = (PdfStream) new PdfStream().makeIndirect(document);
81+
PdfResources resources = new PdfResources();
82+
PdfCanvas pdfCanvas = new PdfCanvas(stream, resources, document);
83+
return new Canvas(pdfCanvas, new Rectangle(100, 100));
84+
}
85+
}
5086
}

0 commit comments

Comments
 (0)