added extra classpath manifest attribute
This commit is contained in:
@@ -1,24 +1,27 @@
|
||||
package net.woggioni.envelope;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.security.DigestInputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.Map;
|
||||
import java.util.MissingFormatArgumentException;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.CRC32;
|
||||
import java.util.zip.ZipEntry;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import java.io.IOException;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class Common {
|
||||
@@ -114,4 +117,144 @@ public class Common {
|
||||
OutputStream result = new FileOutputStream(file);
|
||||
return buffered ? new BufferedOutputStream(result) : result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param template Template text containing the variables to be replaced by this method. <br>
|
||||
* Variables follow the format ${variable_name}. <br>
|
||||
* Example: <br>
|
||||
* "This template was created by ${author}."
|
||||
* @param valuesMap A hashmap with the values of the variables to be replaced. <br>
|
||||
* The key is the variable name and the value is the value to be replaced in the template. <br>
|
||||
* Example: <br>
|
||||
* {"author" => "John Doe"}
|
||||
* @return The template text (String) with the variable names replaced by the values passed in the map. <br>
|
||||
* If any of the variable names is not contained in the map it will be replaced by an empty string. <br>
|
||||
* Example: <br>
|
||||
* "This template was created by John Doe."
|
||||
*/
|
||||
public static String renderTemplate(String template, Map<String, Object> valuesMap) {
|
||||
return renderTemplate(template, valuesMap, null);
|
||||
}
|
||||
|
||||
|
||||
public static int indexOfWithEscape(String haystack, char needle, char escape, int begin, int end) {
|
||||
int result = -1;
|
||||
int cursor = begin;
|
||||
if (end == 0) {
|
||||
end = haystack.length();
|
||||
}
|
||||
int escapeCount = 0;
|
||||
while (cursor < end) {
|
||||
char c = haystack.charAt(cursor);
|
||||
if (escapeCount > 0) {
|
||||
--escapeCount;
|
||||
if (c == escape) {
|
||||
result = -1;
|
||||
}
|
||||
} else if (escapeCount == 0) {
|
||||
if (c == escape) {
|
||||
++escapeCount;
|
||||
}
|
||||
if (c == needle) {
|
||||
result = cursor;
|
||||
}
|
||||
}
|
||||
if (result >= 0 && escapeCount == 0) {
|
||||
break;
|
||||
}
|
||||
++cursor;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String renderTemplate(
|
||||
String template,
|
||||
Map<String, Object> valuesMap,
|
||||
Map<String, Map<String, Object>> dictMap) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Object absent = new Object();
|
||||
|
||||
int cursor = 0;
|
||||
TokenScanner tokenScanner = new TokenScanner(template, '$', '$');
|
||||
while (cursor < template.length()) {
|
||||
tokenScanner.next();
|
||||
int nextPlaceHolder;
|
||||
switch (tokenScanner.getTokenType()) {
|
||||
case TOKEN: {
|
||||
nextPlaceHolder = tokenScanner.getTokenIndex();
|
||||
while (cursor < nextPlaceHolder) {
|
||||
char ch = template.charAt(cursor++);
|
||||
sb.append(ch);
|
||||
}
|
||||
if (cursor + 1 < template.length() && template.charAt(cursor + 1) == '{') {
|
||||
String key;
|
||||
String context = null;
|
||||
String defaultValue = null;
|
||||
Object value;
|
||||
int end = template.indexOf('}', cursor + 1);
|
||||
int colon;
|
||||
if (dictMap == null)
|
||||
colon = -1;
|
||||
else {
|
||||
colon = indexOfWithEscape(template, ':', '\\', cursor + 1, template.length());
|
||||
if (colon >= end) colon = -1;
|
||||
}
|
||||
if (colon < 0) {
|
||||
key = template.substring(cursor + 2, end);
|
||||
value = valuesMap.getOrDefault(key, absent);
|
||||
} else {
|
||||
context = template.substring(cursor + 2, colon);
|
||||
int secondColon = indexOfWithEscape(template, ':', '\\', colon + 1, end);
|
||||
if (secondColon < 0) {
|
||||
key = template.substring(colon + 1, end);
|
||||
} else {
|
||||
key = template.substring(colon + 1, secondColon);
|
||||
defaultValue = template.substring(secondColon + 1, end);
|
||||
}
|
||||
value = Optional.ofNullable(dictMap.get(context))
|
||||
.map(m -> m.get(key))
|
||||
.orElse(absent);
|
||||
}
|
||||
if (value != absent) {
|
||||
sb.append(value.toString());
|
||||
} else {
|
||||
if (defaultValue != null) {
|
||||
sb.append(defaultValue);
|
||||
} else {
|
||||
throw new MissingFormatArgumentException(
|
||||
String.format("Missing value for placeholder '%s'",
|
||||
context == null ? key : context + ':' + key
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
cursor = end + 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESCAPE:
|
||||
nextPlaceHolder = tokenScanner.getTokenIndex();
|
||||
while (cursor < nextPlaceHolder) {
|
||||
char ch = template.charAt(cursor++);
|
||||
sb.append(ch);
|
||||
}
|
||||
cursor = nextPlaceHolder + 1;
|
||||
sb.append(template.charAt(cursor++));
|
||||
break;
|
||||
case END:
|
||||
default:
|
||||
nextPlaceHolder = template.length();
|
||||
while (cursor < nextPlaceHolder) {
|
||||
char ch = template.charAt(cursor++);
|
||||
sb.append(ch);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static <T> Stream<T> opt2Stream(Optional<T> opt) {
|
||||
return opt.map(Stream::of).orElse(Stream.empty());
|
||||
}
|
||||
}
|
||||
|
@@ -1,9 +1,10 @@
|
||||
package net.woggioni.envelope;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class Constants {
|
||||
@@ -16,10 +17,12 @@ public class Constants {
|
||||
public static final String SYSTEM_PROPERTIES_FILE = METADATA_FOLDER + "/system.properties";
|
||||
|
||||
public static final String LIBRARIES_TOC = METADATA_FOLDER + "/libraries.txt";
|
||||
public static final char EXTRA_CLASSPATH_ENTRY_SEPARATOR = ';';
|
||||
|
||||
public static class ManifestAttributes {
|
||||
public static final String MAIN_MODULE = "Executable-Jar-Main-Module";
|
||||
public static final String MAIN_CLASS = "Executable-Jar-Main-Class";
|
||||
public static final String EXTRA_CLASSPATH = "Executable-Jar-Extra-Classpath";
|
||||
public static final String ENTRY_HASH = "SHA-256-Digest";
|
||||
}
|
||||
|
||||
|
74
common/src/main/java/net/woggioni/envelope/TokenScanner.java
Normal file
74
common/src/main/java/net/woggioni/envelope/TokenScanner.java
Normal file
@@ -0,0 +1,74 @@
|
||||
package net.woggioni.envelope;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
public class TokenScanner {
|
||||
|
||||
public enum TokenType {
|
||||
ESCAPE, TOKEN, END;
|
||||
}
|
||||
private final String haystack;
|
||||
private final char needle;
|
||||
private final char escape;
|
||||
private int begin;
|
||||
private final int end;
|
||||
|
||||
@Getter
|
||||
private int tokenIndex = -1;
|
||||
|
||||
@Getter
|
||||
private TokenType tokenType = null;
|
||||
|
||||
public TokenScanner(String haystack, char needle, char escape, int begin, int end) {
|
||||
this.haystack = haystack;
|
||||
this.needle = needle;
|
||||
this.escape = escape;
|
||||
this.begin = begin;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
public TokenScanner(String haystack, char needle, char escape, int begin) {
|
||||
this(haystack, needle, escape, begin, haystack.length());
|
||||
}
|
||||
|
||||
public TokenScanner(String haystack, char needle, char escape) {
|
||||
this(haystack, needle, escape, 0, haystack.length());
|
||||
}
|
||||
|
||||
public void next() {
|
||||
int result = -1;
|
||||
int cursor = begin;
|
||||
int escapeCount = 0;
|
||||
while(true) {
|
||||
if(cursor < end) {
|
||||
char c = haystack.charAt(cursor);
|
||||
if (escapeCount > 0) {
|
||||
--escapeCount;
|
||||
if(c == escape || c == needle) {
|
||||
tokenIndex = cursor - 1;
|
||||
tokenType = TokenType.ESCAPE;
|
||||
break;
|
||||
}
|
||||
} else if (escapeCount == 0) {
|
||||
if (c == escape) {
|
||||
++escapeCount;
|
||||
}
|
||||
if (c == needle) {
|
||||
result = cursor;
|
||||
}
|
||||
}
|
||||
if (result >= 0 && escapeCount == 0) {
|
||||
tokenIndex = result;
|
||||
tokenType = TokenType.TOKEN;
|
||||
break;
|
||||
}
|
||||
++cursor;
|
||||
} else {
|
||||
tokenIndex = result;
|
||||
tokenType = result < 0 ? TokenType.END :TokenType.TOKEN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
begin = cursor + 1;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user