Skip to content

Commit 860b23b

Browse files
committed
Add caching to LOTL mechanism + finalize api
DEVSIX-9263
1 parent bf03cda commit 860b23b

File tree

88 files changed

+322440
-1061
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

88 files changed

+322440
-1061
lines changed
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
This file is part of the iText (R) project.
3+
Copyright (c) 1998-2025 Apryse Group NV
4+
Authors: Apryse Software.
5+
6+
This program is offered under a commercial and under the AGPL license.
7+
For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below.
8+
9+
AGPL licensing:
10+
This program is free software: you can redistribute it and/or modify
11+
it under the terms of the GNU Affero General Public License as published by
12+
the Free Software Foundation, either version 3 of the License, or
13+
(at your option) any later version.
14+
15+
This program is distributed in the hope that it will be useful,
16+
but WITHOUT ANY WARRANTY; without even the implied warranty of
17+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18+
GNU Affero General Public License for more details.
19+
20+
You should have received a copy of the GNU Affero General Public License
21+
along with this program. If not, see <https://www.gnu.org/licenses/>.
22+
*/
23+
package com.itextpdf.commons.utils;
24+
25+
import java.util.ArrayList;
26+
import java.util.List;
27+
import java.util.concurrent.Callable;
28+
import java.util.concurrent.ExecutorService;
29+
import java.util.concurrent.Executors;
30+
import java.util.concurrent.Future;
31+
32+
/**
33+
* Utility class for running actions in parallel using multiple threads.
34+
* This class provides a method to execute a list of Callable actions in parallel
35+
* and collect their results.
36+
*/
37+
public class MultiThreadingUtil {
38+
39+
private MultiThreadingUtil() {
40+
// Private constructor to prevent instantiation
41+
}
42+
43+
/**
44+
* Runs a list of Callable actions in parallel using a fixed thread pool.
45+
*
46+
* @param actions the list of Callable actions to be executed
47+
* @param numberOfThreads the number of threads to use for parallel execution
48+
* @param <T> the type of the result returned by the Callable actions
49+
*
50+
* @return a list of results from the executed actions
51+
*/
52+
public static <T> List<T> runActionsParallel(List<Callable<T>> actions, int numberOfThreads) {
53+
final int amountOfThreads = Math.max(
54+
Math.min(numberOfThreads, Runtime.getRuntime().availableProcessors()), 1);
55+
ExecutorService service = Executors.newFixedThreadPool(amountOfThreads);
56+
try {
57+
List<T> results = new ArrayList<>();
58+
List<Future<T>> f = service.invokeAll(actions);
59+
for (Future<T> tFuture : f) {
60+
try {
61+
T future = tFuture.get();
62+
if (future != null) {
63+
results.add(future);
64+
}
65+
} catch (Exception e) {
66+
throw new RuntimeException("Error while executing action in parallel", e);
67+
}
68+
}
69+
return results;
70+
} catch (InterruptedException e) {
71+
Thread.currentThread().interrupt();
72+
throw new RuntimeException("Thread was interrupted while executing actions in parallel", e);
73+
} finally {
74+
service.shutdown();
75+
}
76+
}
77+
78+
}

commons/src/main/java/com/itextpdf/commons/utils/SystemUtil.java

Lines changed: 52 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ public final class SystemUtil {
4141

4242
private final static String SPLIT_REGEX = "((\".+?\"|[^'\\s]|'.+?')+)\\s*";
4343

44+
private SystemUtil() {
45+
// Empty constructor.
46+
}
47+
4448
/**
4549
* Gets seed as long value of current time in milliseconds.
4650
*
@@ -59,10 +63,6 @@ public static int getTimeBasedIntSeed() {
5963
return (int) System.currentTimeMillis();
6064
}
6165

62-
private SystemUtil() {
63-
// Empty constructor.
64-
}
65-
6666
/**
6767
* Should be used in relative constructs (for example to check how many milliseconds have passed).
6868
*
@@ -75,6 +75,15 @@ public static long getRelativeTimeMillis() {
7575
return System.currentTimeMillis();
7676
}
7777

78+
/**
79+
* Gets current time in milliseconds since the epoch (January 1, 1970, 00:00:00 GMT).
80+
*
81+
* @return current time in milliseconds.
82+
*/
83+
public static long currentTimeMillis() {
84+
return System.currentTimeMillis();
85+
}
86+
7887
/**
7988
* Gets free available memory for JDK.
8089
*
@@ -88,6 +97,7 @@ public static long getFreeMemory() {
8897
* Gets either java property or environment variable with given name.
8998
*
9099
* @param name the name of either java property or environment variable.
100+
*
91101
* @return property or variable value or null if there is no such.
92102
*/
93103
public static String getPropertyOrEnvironmentVariable(String name) {
@@ -99,88 +109,96 @@ public static String getPropertyOrEnvironmentVariable(String name) {
99109
}
100110

101111
/**
102-
* Executes the specified command and arguments in a separate process with the specified environment and working directory.
112+
* Executes the specified command and arguments in a separate process with the specified environment and working
113+
* directory.
103114
* This method checks that exec is a valid operating system command. Which commands are valid is system-dependent,
104115
* but at the very least the command must be a non-empty and non-null.
105116
* The subprocess inherits the environment settings of the current process.
106-
* A minimal set of system dependent environment variables may be required to start a process on some operating systems.
117+
* A minimal set of system dependent environment variables may be required to start a process on some operating
118+
* systems.
107119
* The working directory of the new subprocess is the current working directory of the current process.
108120
*
109-
* @param exec a specified system command.
121+
* @param exec a specified system command.
110122
* @param params a parameters for the specifed system command.
111123
*
112124
* @return true if subprocess was successfully executed, false otherwise.
113125
*
114-
* @throws IOException if any I/O error occurs.
126+
* @throws IOException if any I/O error occurs.
115127
* @throws InterruptedException if process was interrupted.
116128
*/
117129
public static boolean runProcessAndWait(String exec, String params) throws IOException, InterruptedException {
118130
return runProcessAndWait(exec, params, null);
119131
}
120132

121133
/**
122-
* Executes the specified command and arguments in a separate process with the specified environment and working directory.
134+
* Executes the specified command and arguments in a separate process with the specified environment and working
135+
* directory.
123136
* This method checks that exec is a valid operating system command. Which commands are valid is system-dependent,
124137
* but at the very least the command must be a non-empty and non-null.
125138
* The subprocess inherits the environment settings of the current process.
126-
* A minimal set of system dependent environment variables may be required to start a process on some operating systems.
139+
* A minimal set of system dependent environment variables may be required to start a process on some operating
140+
* systems.
127141
* The working directory of the new subprocess is specified by workingDirPath.
128142
* If dir is null, the subprocess inherits the current working directory of the current process.
129143
*
130-
* @param exec a specified system command.
131-
* @param params a parameters for the specifed system command.
144+
* @param exec a specified system command.
145+
* @param params a parameters for the specifed system command.
132146
* @param workingDirPath working dir for subprocess.
133147
*
134148
* @return true if subprocess was successfully executed, false otherwise.
135149
*
136-
* @throws IOException if any I/O error occurs.
150+
* @throws IOException if any I/O error occurs.
137151
* @throws InterruptedException if process was interrupted.
138152
*/
139153
public static boolean runProcessAndWait(String exec, String params,
140-
String workingDirPath) throws IOException, InterruptedException {
154+
String workingDirPath) throws IOException, InterruptedException {
141155
return runProcessAndGetExitCode(exec, params, workingDirPath) == 0;
142156
}
143157

144158
/**
145-
* Executes the specified command and arguments in a separate process with the specified environment and working directory.
159+
* Executes the specified command and arguments in a separate process with the specified environment and working
160+
* directory.
146161
* This method checks that exec is a valid operating system command. Which commands are valid is system-dependent,
147162
* but at the very least the command must be a non-empty and non-null.
148163
* The subprocess inherits the environment settings of the current process.
149-
* A minimal set of system dependent environment variables may be required to start a process on some operating systems.
164+
* A minimal set of system dependent environment variables may be required to start a process on some operating
165+
* systems.
150166
* The working directory of the new subprocess is the current working directory of the current process.
151167
*
152-
* @param exec a specified system command.
168+
* @param exec a specified system command.
153169
* @param params a parameters for the specifed system command.
154170
*
155171
* @return exit code.
156172
*
157-
* @throws IOException if any I/O error occurs.
173+
* @throws IOException if any I/O error occurs.
158174
* @throws InterruptedException if process was interrupted.
159175
*/
160176
public static int runProcessAndGetExitCode(String exec, String params) throws IOException, InterruptedException {
161177
return runProcessAndGetExitCode(exec, params, null);
162178
}
163179

164180
/**
165-
* Executes the specified command and arguments in a separate process with the specified environment and working directory.
181+
* Executes the specified command and arguments in a separate process with the specified environment and working
182+
* directory.
166183
* This method checks that exec is a valid operating system command. Which commands are valid is system-dependent,
167184
* but at the very least the command must be a non-empty and non-null.
168185
* The subprocess inherits the environment settings of the current process.
169-
* A minimal set of system dependent environment variables may be required to start a process on some operating systems.
186+
* A minimal set of system dependent environment variables may be required to start a process on some operating
187+
* systems.
170188
* The working directory of the new subprocess is specified by workingDirPath.
171189
* If dir is null, the subprocess inherits the current working directory of the current process.
172190
*
173-
* @param exec a specified system command.
174-
* @param params a parameters for the specifed system command.
191+
* @param exec a specified system command.
192+
* @param params a parameters for the specifed system command.
175193
* @param workingDirPath working dir for subprocess.
176194
*
177195
* @return exit code.
178196
*
179-
* @throws IOException if any I/O error occurs.
197+
* @throws IOException if any I/O error occurs.
180198
* @throws InterruptedException if process was interrupted.
181199
*/
182200
public static int runProcessAndGetExitCode(String exec, String params,
183-
String workingDirPath) throws IOException, InterruptedException {
201+
String workingDirPath) throws IOException, InterruptedException {
184202
Process p = runProcess(exec, params, workingDirPath);
185203
System.out.println(getProcessOutput(p));
186204
return p.waitFor();
@@ -192,12 +210,13 @@ public static int runProcessAndGetExitCode(String exec, String params,
192210
* This method checks that exec is a valid operating system command. Which commands are valid is system-dependent,
193211
* but at the very least the command must be a non-empty and non-null.
194212
* The subprocess inherits the environment settings of the current process.
195-
* A minimal set of system dependent environment variables may be required to start a process on some operating systems.
213+
* A minimal set of system dependent environment variables may be required to start a process on some operating
214+
* systems.
196215
* The working directory of the new subprocess is specified by workingDirPath.
197216
* If dir is null, the subprocess inherits the current working directory of the current process.
198217
*
199218
* @param command a specified system command.
200-
* @param params a parameters for the specifed system command.
219+
* @param params a parameters for the specifed system command.
201220
*
202221
* @return subprocess output result.
203222
*
@@ -213,12 +232,13 @@ public static String runProcessAndGetOutput(String command, String params) throw
213232
* This method checks that exec is a valid operating system command. Which commands are valid is system-dependent,
214233
* but at the very least the command must be a non-empty and non-null.
215234
* The subprocess inherits the environment settings of the current process.
216-
* A minimal set of system dependent environment variables may be required to start a process on some operating systems.
235+
* A minimal set of system dependent environment variables may be required to start a process on some operating
236+
* systems.
217237
* The working directory of the new subprocess is specified by workingDirPath.
218238
* If dir is null, the subprocess inherits the current working directory of the current process.
219239
*
220240
* @param execPath a specified system command.
221-
* @param params a parameters for the specifed system command.
241+
* @param params a parameters for the specifed system command.
222242
*
223243
* @return subprocess errors as {@code StringBuilder}.
224244
*
@@ -234,16 +254,17 @@ public static StringBuilder runProcessAndCollectErrors(String execPath, String p
234254
* This method checks that exec is a valid operating system command. Which commands are valid is system-dependent,
235255
* but at the very least the command must be a non-empty and non-null.
236256
* The subprocess inherits the environment settings of the current process.
237-
* A minimal set of system dependent environment variables may be required to start a process on some operating systems.
257+
* A minimal set of system dependent environment variables may be required to start a process on some operating
258+
* systems.
238259
* The working directory of the new subprocess is specified by workingDirPath.
239260
* If dir is null, the subprocess inherits the current working directory of the current process.
240261
*
241262
* @param command a specified system command.
242-
* @param params a parameters for the specifed system command.
263+
* @param params a parameters for the specifed system command.
243264
*
244265
* @return process info instance.
245266
*
246-
* @throws IOException if any I/O error occurs.
267+
* @throws IOException if any I/O error occurs.
247268
* @throws InterruptedException if process was interrupted.
248269
*/
249270
public static ProcessInfo runProcessAndGetProcessInfo(String command, String params) throws IOException,
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
This file is part of the iText (R) project.
3+
Copyright (c) 1998-2025 Apryse Group NV
4+
Authors: Apryse Software.
5+
6+
This program is offered under a commercial and under the AGPL license.
7+
For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below.
8+
9+
AGPL licensing:
10+
This program is free software: you can redistribute it and/or modify
11+
it under the terms of the GNU Affero General Public License as published by
12+
the Free Software Foundation, either version 3 of the License, or
13+
(at your option) any later version.
14+
15+
This program is distributed in the hope that it will be useful,
16+
but WITHOUT ANY WARRANTY; without even the implied warranty of
17+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18+
GNU Affero General Public License for more details.
19+
20+
You should have received a copy of the GNU Affero General Public License
21+
along with this program. If not, see <https://www.gnu.org/licenses/>.
22+
*/
23+
package com.itextpdf.commons.utils;
24+
25+
import java.util.Timer;
26+
27+
/**
28+
* Utility class for creating and managing timers.
29+
*/
30+
public class TimerUtil {
31+
32+
private TimerUtil() {
33+
// Private constructor to prevent instantiation
34+
}
35+
36+
/**
37+
* Creates a new Timer instance.
38+
*
39+
* @param task the task to be executed by the timer
40+
* @param delay the delay before the task is executed for the first time
41+
* @param period the period between subsequent executions of the task
42+
*
43+
* @return a Timer instance that executes the task at the specified interval
44+
*/
45+
46+
public static Timer newTimerWithRecurringTask(Action task, long delay, long period) {
47+
Timer t = new Timer(true);
48+
t.scheduleAtFixedRate(new java.util.TimerTask() {
49+
@Override
50+
public void run() {
51+
task.execute();
52+
}
53+
}, delay, period);
54+
return t;
55+
}
56+
57+
/**
58+
* Stops the given Timer instance.
59+
*
60+
* @param timer the Timer instance to stop
61+
*/
62+
public static void stopTimer(Timer timer) {
63+
if (timer != null) {
64+
timer.cancel();
65+
timer.purge();
66+
}
67+
}
68+
69+
}

commons/src/sharpenconfig/java/com/itextpdf/commons/SharpenConfigMapping.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,12 @@ private void mapStandardJavaToUtil(MappingConfigurator configurator) {
327327
for (String name : streamImplementations) {
328328
configurator.addCustomUsingForMethodInvocation(name + ".sorted", Collections.singletonList("iText.Commons.Utils.Collections"));
329329
}
330+
331+
332+
333+
configurator.mapType("java.util.Timer", "System.Threading.Timer");
334+
configurator.mapType("java.util.concurrent.Callable<>", "Func");
335+
configurator.mapMethod("java.util.concurrent.Callable.call", "Invoke");
330336
}
331337

332338
private void mapBouncyCastle(MappingConfigurator configurator) {

0 commit comments

Comments
 (0)