Skip to content

Commit 44d7a03

Browse files
Samuel HuylebroeckIdamkinI
authored andcommitted
Version checking
DEVSIX-1698
1 parent f2eea8e commit 44d7a03

File tree

2 files changed

+223
-22
lines changed

2 files changed

+223
-22
lines changed
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
package com.itextpdf.kernel;
2+
3+
import com.itextpdf.io.util.MessageFormatUtil;
4+
5+
import java.util.ArrayList;
6+
import java.util.Collections;
7+
import java.util.List;
8+
9+
/**
10+
* Exception class for License-key version exceptions throw in the Version class
11+
*/
12+
public class LicenseVersionException extends RuntimeException{
13+
14+
public static final String NO_I_TEXT7_LICENSE_IS_LOADED_BUT_AN_I_TEXT5_LICENSE_IS_LOADED ="No iText7 License is loaded but an iText5 license is loaded.";
15+
public static final String THE_MAJOR_VERSION_OF_THE_LICENSE_0_IS_LOWER_THAN_THE_MAJOR_VERSION_1_OF_THE_CORE_LIBRARY ="The major version of the license ({0}) is lower than the major version ({1}) of the Core library.";
16+
public static final String THE_MAJOR_VERSION_OF_THE_LICENSE_0_IS_HIGHER_THAN_THE_MAJOR_VERSION_1_OF_THE_CORE_LIBRARY ="The major version of the license ({0}) is higher than the major version ({1}) of the Core library.";
17+
18+
public static final String THE_MINOR_VERSION_OF_THE_LICENSE_0_IS_LOWER_THAN_THE_MINOR_VERSION_1_OF_THE_CORE_LIBRARY ="The minor version of the license ({0}) is lower than the minor version ({1}) of the Core library.";
19+
public static final String THE_MINOR_VERSION_OF_THE_LICENSE_0_IS_HIGHER_THAN_THE_MINOR_VERSION_1_OF_THE_CORE_LIBRARY ="The minor version of the license ({0}) is higher than the minor version ({1}) of the Core library.";
20+
21+
public static final String VERSION_STRING_IS_EMPTY_AND_CANNOT_BE_PARSED = "Version string is empty and cannot be parsed.";
22+
public static final String MAJOR_VERSION_IS_NOT_NUMERIC ="Major version is not numeric";
23+
public static final String MINOR_VERSION_IS_NOT_NUMERIC ="Minor version is not numeric";
24+
public static final String UNKNOWN_EXCEPTION_WHEN_CHECKING_LICENSE_VERSION ="Unknown Exception when checking License version";
25+
26+
public static final String LICENSE_FILE_NOT_LOADED = "License file not loaded.";
27+
/**
28+
* Object for more details
29+
*/
30+
protected Object object;
31+
32+
private List<Object> messageParams;
33+
34+
/**
35+
* Creates a new instance of PdfException.
36+
*
37+
* @param message the detail message.
38+
*/
39+
public LicenseVersionException(String message) {
40+
super(message);
41+
}
42+
43+
/**
44+
* Creates a new instance of PdfException.
45+
*
46+
* @param cause the cause (which is saved for later retrieval by {@link #getCause()} method).
47+
*/
48+
public LicenseVersionException(Throwable cause) {
49+
this(UNKNOWN_EXCEPTION_WHEN_CHECKING_LICENSE_VERSION, cause);
50+
}
51+
52+
/**
53+
* Creates a new instance of PdfException.
54+
*
55+
* @param message the detail message.
56+
* @param obj an object for more details.
57+
*/
58+
public LicenseVersionException(String message, Object obj) {
59+
this(message);
60+
this.object = obj;
61+
}
62+
63+
/**
64+
* Creates a new instance of PdfException.
65+
*
66+
* @param message the detail message.
67+
* @param cause the cause (which is saved for later retrieval by {@link #getCause()} method).
68+
*/
69+
public LicenseVersionException(String message, Throwable cause) {
70+
super(message, cause);
71+
}
72+
73+
/**
74+
* Creates a new instance of PdfException.
75+
*
76+
* @param message the detail message.
77+
* @param cause the cause (which is saved for later retrieval by {@link #getCause()} method).
78+
* @param obj an object for more details.
79+
*/
80+
public LicenseVersionException(String message, Throwable cause, Object obj) {
81+
this(message, cause);
82+
this.object = obj;
83+
}
84+
85+
@Override
86+
public String getMessage() {
87+
if (messageParams == null || messageParams.size() == 0) {
88+
return super.getMessage();
89+
} else {
90+
return MessageFormatUtil.format(super.getMessage(), getMessageParams());
91+
}
92+
}
93+
94+
/**
95+
* Sets additional params for Exception message.
96+
*
97+
* @param messageParams additional params.
98+
* @return object itself.
99+
*/
100+
public LicenseVersionException setMessageParams(Object... messageParams) {
101+
this.messageParams = new ArrayList<>();
102+
Collections.addAll(this.messageParams, messageParams);
103+
return this;
104+
}
105+
106+
/**
107+
* Gets additional params for Exception message.
108+
*/
109+
protected Object[] getMessageParams() {
110+
Object[] parameters = new Object[messageParams.size()];
111+
for (int i = 0; i < messageParams.size(); i++) {
112+
parameters[i] = messageParams.get(i);
113+
}
114+
return parameters;
115+
}
116+
}

kernel/src/main/java/com/itextpdf/kernel/Version.java

Lines changed: 107 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ This file is part of the iText (R) project.
4343
*/
4444
package com.itextpdf.kernel;
4545

46+
import java.lang.reflect.InvocationTargetException;
4647
import java.lang.reflect.Method;
4748

4849
/**
@@ -67,7 +68,7 @@ public final class Version {
6768
* iText is a registered trademark by iText Group NV.
6869
* Please don't change this constant.
6970
*/
70-
private static String iText = "iText\u00ae";
71+
private static String iTextProductName = "iText\u00ae";
7172
/**
7273
* This String contains the version number of this iText release.
7374
* For debugging purposes, we request you NOT to change this constant.
@@ -79,7 +80,7 @@ public final class Version {
7980
* iText Group requests that you retain the iText producer line
8081
* in every PDF that is created or manipulated using iText.
8182
*/
82-
private String iTextVersion = iText + " " + release + " \u00a92000-2017 iText Group NV";
83+
private String producerLine = iTextProductName + " " + release + " \u00a92000-2017 iText Group NV";
8384

8485
/**
8586
* The license key.
@@ -98,14 +99,9 @@ public static Version getInstance() {
9899
version = new Version();
99100
synchronized (version) {
100101
try {
101-
String licenseeInfoMethodName = "getLicenseeInfoForVersion";
102-
Class<?> klass = getLicenseKeyClass();
103-
if (klass != null) {
104-
Class[] cArg = {String.class};
105-
Method m = klass.getMethod(licenseeInfoMethodName,cArg);
106-
String coreVersion = release;
107-
Object[] args = {coreVersion};
108-
String[] info = (String[]) m.invoke(klass.newInstance(), args);
102+
String coreVersion = release;
103+
String[] info = getLicenseeInfoFromLicenseKey(coreVersion);
104+
if(info != null){
109105
if (info[3] != null && info[3].trim().length() > 0) {
110106
version.key = info[3];
111107
} else {
@@ -119,14 +115,13 @@ public static Version getInstance() {
119115

120116
if (info.length > 6) {
121117
if (info[6] != null && info[6].trim().length() > 0) {
122-
if (! release.startsWith(info[6])) {
123-
throw new IllegalArgumentException("Your license key version doesn't match the iText version.");
124-
}
118+
//Compare versions with this release versions
119+
checkLicenseVersion(coreVersion, info[6]);
125120
}
126121
}
127122

128123
if (info[4] != null && info[4].trim().length() > 0) {
129-
version.iTextVersion = info[4];
124+
version.producerLine = info[4];
130125
} else if (info[2] != null && info[2].trim().length() > 0) {
131126
version.addLicensedPostfix(info[2]);
132127
} else if (info[0] != null && info[0].trim().length() > 0) {
@@ -140,9 +135,20 @@ public static Version getInstance() {
140135
} else {
141136
version.addAGPLPostfix(null);
142137
}
143-
} catch (IllegalArgumentException iae) {
144-
version.addAGPLPostfix(iae.getCause());
138+
//Catch the exception
139+
} catch(LicenseVersionException lve) {
140+
//Rethrow license version exceptions
141+
throw lve;
142+
}catch(ClassNotFoundException cnfe){
143+
//License key library not on classpath, switch to AGPL
144+
version.addAGPLPostfix(null);
145145
} catch (Exception e) {
146+
//Check if an iText5 license is loaded
147+
if(e.getCause() != null && e.getCause().getMessage().equals(LicenseVersionException.LICENSE_FILE_NOT_LOADED)) {
148+
if (isiText5licenseLoaded()) {
149+
throw new LicenseVersionException(LicenseVersionException.NO_I_TEXT7_LICENSE_IS_LOADED_BUT_AN_I_TEXT5_LICENSE_IS_LOADED);
150+
}
151+
}
146152
version.addAGPLPostfix(e.getCause());
147153
}
148154
}
@@ -174,7 +180,7 @@ public static boolean isExpired() {
174180
* @return the product name
175181
*/
176182
public String getProduct() {
177-
return iText;
183+
return iTextProductName;
178184
}
179185

180186
/**
@@ -197,7 +203,7 @@ public String getRelease() {
197203
* @return iText version
198204
*/
199205
public String getVersion() {
200-
return iTextVersion;
206+
return producerLine;
201207
}
202208

203209
/**
@@ -210,16 +216,16 @@ public String getKey() {
210216
}
211217

212218
private void addLicensedPostfix(String ownerName) {
213-
iTextVersion += " (" + ownerName;
219+
producerLine += " (" + ownerName;
214220
if (! key.toLowerCase().startsWith("trial")) {
215-
iTextVersion += "; licensed version)";
221+
producerLine += "; licensed version)";
216222
} else {
217-
iTextVersion += "; " + key + ")";
223+
producerLine += "; " + key + ")";
218224
}
219225
}
220226

221227
private void addAGPLPostfix(Throwable cause) {
222-
iTextVersion += AGPL;
228+
producerLine += AGPL;
223229

224230
if (cause != null && cause.getMessage() != null && cause.getMessage().contains("expired")) {
225231
expired = true;
@@ -231,4 +237,83 @@ private static Class<?> getLicenseKeyClass() throws ClassNotFoundException {
231237
return Class.forName(licenseKeyClassFullName);
232238
}
233239

240+
private static void checkLicenseVersion(String coreVersionString, String licenseVersionString){
241+
String[] coreVersions = parseVersionString(coreVersionString);
242+
String[] licenseVersions = parseVersionString(licenseVersionString);
243+
244+
int coreMajor = Integer.parseInt(coreVersions[0]);
245+
int coreMinor = Integer.parseInt(coreVersions[1]);
246+
247+
int licenseMajor = Integer.parseInt(licenseVersions[0]);
248+
int licenseMinor = Integer.parseInt(licenseVersions[1]);
249+
//Major version check
250+
if(licenseMajor < coreMajor){
251+
throw new LicenseVersionException(LicenseVersionException.THE_MAJOR_VERSION_OF_THE_LICENSE_0_IS_LOWER_THAN_THE_MAJOR_VERSION_1_OF_THE_CORE_LIBRARY).setMessageParams(licenseMajor,coreMajor);
252+
}
253+
if(licenseMajor>coreMajor){
254+
throw new LicenseVersionException(LicenseVersionException.THE_MAJOR_VERSION_OF_THE_LICENSE_0_IS_HIGHER_THAN_THE_MAJOR_VERSION_1_OF_THE_CORE_LIBRARY).setMessageParams(licenseMajor,coreMajor);
255+
256+
}
257+
//Minor version check
258+
if(licenseMinor < coreMinor){
259+
throw new LicenseVersionException(LicenseVersionException.THE_MINOR_VERSION_OF_THE_LICENSE_0_IS_LOWER_THAN_THE_MINOR_VERSION_1_OF_THE_CORE_LIBRARY).setMessageParams(licenseMinor,coreMinor);
260+
}
261+
262+
}
263+
264+
private static String[] parseVersionString(String version){
265+
String splitRegex = "\\.";
266+
String[] split = version.split(splitRegex);
267+
//Guard for empty versions and throw exceptions
268+
if(split.length == 0){
269+
throw new LicenseVersionException(LicenseVersionException.VERSION_STRING_IS_EMPTY_AND_CANNOT_BE_PARSED);
270+
}
271+
//Desired Format: X.Y.Z-....
272+
//Also catch X, X.Y-...
273+
String major = split[0];
274+
String minor ="0"; //If no minor version is present, default to 0
275+
if(split.length > 1) {
276+
minor = split[1].substring(0);
277+
}
278+
//Check if both values are numbers
279+
if(!isVersionNumeric(major)) throw new LicenseVersionException(LicenseVersionException.MAJOR_VERSION_IS_NOT_NUMERIC);
280+
if(!isVersionNumeric(minor)) throw new LicenseVersionException(LicenseVersionException.MINOR_VERSION_IS_NOT_NUMERIC);
281+
return new String[]{major,minor};
282+
}
283+
284+
private static String[] getLicenseeInfoFromLicenseKey(String validatorKey) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
285+
String licenseeInfoMethodName = "getLicenseeInfoForVersion";
286+
Class<?> klass = getLicenseKeyClass();
287+
if (klass != null) {
288+
Class[] cArg = {String.class};
289+
Method m = klass.getMethod(licenseeInfoMethodName, cArg);
290+
Object[] args = {validatorKey};
291+
String[] info = (String[]) m.invoke(klass.newInstance(), args);
292+
return info;
293+
}
294+
return null;
295+
}
296+
297+
private static boolean isiText5licenseLoaded(){
298+
String validatorKey5 = "5";
299+
boolean result = false;
300+
try {
301+
String[] info = getLicenseeInfoFromLicenseKey(validatorKey5);
302+
result = true;
303+
}catch(Exception e){
304+
//TODO: Log this exception?
305+
}
306+
return result;
307+
}
308+
309+
private static boolean isVersionNumeric(String version){
310+
//I did not want to introduce an extra dependency on apache.commons in order to use StringUtils.
311+
//This small method is not the most optimal, but it should do for release
312+
try{
313+
Double.parseDouble(version);
314+
return true;
315+
}catch(NumberFormatException e){
316+
return false;
317+
}
318+
}
234319
}

0 commit comments

Comments
 (0)