diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/model/ActionHook.java b/src/main/java/ch/sbb/polarion/extension/interceptor/model/ActionHook.java index a8f94ae..d3f2ce9 100644 --- a/src/main/java/ch/sbb/polarion/extension/interceptor/model/ActionHook.java +++ b/src/main/java/ch/sbb/polarion/extension/interceptor/model/ActionHook.java @@ -4,6 +4,7 @@ import ch.sbb.polarion.extension.generic.settings.NamedSettingsRegistry; import ch.sbb.polarion.extension.generic.settings.SettingId; import ch.sbb.polarion.extension.interceptor.settings.HookModel; +import ch.sbb.polarion.extension.interceptor.util.HookManifestUtils; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.polarion.alm.projects.model.IUniqueObject; @@ -14,6 +15,7 @@ import com.polarion.core.util.StringUtils; import lombok.Data; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.lang.reflect.Method; import java.util.Arrays; @@ -38,14 +40,22 @@ public abstract class ActionHook { private String version; private String description; - public ActionHook(ItemType itemType, ActionType actionType, String version, String description) { + public ActionHook(@NotNull ItemType itemType, @NotNull ActionType actionType, @Nullable String description) { + this(Collections.singletonList(itemType), actionType, description); + } + + public ActionHook(@NotNull ItemType itemType, @NotNull ActionType actionType, @Nullable String version, @Nullable String description) { this(Collections.singletonList(itemType), actionType, version, description); } - public ActionHook(List itemTypes, ActionType actionType, String version, String description) { + public ActionHook(@NotNull List itemTypes, @NotNull ActionType actionType, @Nullable String description) { + this(itemTypes, actionType, null, description); + } + + public ActionHook(@NotNull List itemTypes, @NotNull ActionType actionType, @Nullable String version, @Nullable String description) { this.itemTypes = itemTypes; this.actionType = actionType; - this.version = version; + this.version = version == null ? HookManifestUtils.getHookVersion(getClass()) : version; this.description = description; } diff --git a/src/main/java/ch/sbb/polarion/extension/interceptor/util/HookManifestUtils.java b/src/main/java/ch/sbb/polarion/extension/interceptor/util/HookManifestUtils.java new file mode 100644 index 0000000..52d3da8 --- /dev/null +++ b/src/main/java/ch/sbb/polarion/extension/interceptor/util/HookManifestUtils.java @@ -0,0 +1,58 @@ +package ch.sbb.polarion.extension.interceptor.util; + +import ch.sbb.polarion.extension.interceptor.model.ActionHook; +import lombok.experimental.UtilityClass; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.CodeSource; +import java.util.jar.Attributes; +import java.util.jar.JarFile; +import java.util.jar.Manifest; + +@UtilityClass +@SuppressWarnings("unused") +public class HookManifestUtils { + + public static final String BUNDLE_VERSION = "Bundle-Version"; + + public static @Nullable String getHookVersion(@NotNull Class hookClass) { + try { + Manifest manifest = loadManifestByClass(hookClass); + if (manifest != null) { + Attributes attributes = manifest.getMainAttributes(); + return attributes.getValue(BUNDLE_VERSION); + } else { + return null; + } + } catch (IOException | URISyntaxException e) { + throw new IllegalStateException(e); + } + } + + public static @Nullable Manifest loadManifestByClass(@NotNull Class hookClass) throws IOException, URISyntaxException { + CodeSource codeSource = hookClass.getProtectionDomain().getCodeSource(); + + if (codeSource != null) { + URL location = codeSource.getLocation(); + Path jarPath = Paths.get(location.toURI()); + + if (Files.isRegularFile(jarPath)) { + try (JarFile jarFile = new JarFile(jarPath.toFile())) { + return jarFile.getManifest(); + } + } else { + throw new IllegalArgumentException("The class %s is not loaded from a JAR file.".formatted(hookClass.getName())); + } + } else { + throw new IllegalArgumentException("Could not determine the code source location."); + } + } + +} diff --git a/src/main/resources/webapp/interceptor-admin/js/settings.js b/src/main/resources/webapp/interceptor-admin/js/settings.js index 9a72712..30e0fb7 100644 --- a/src/main/resources/webapp/interceptor-admin/js/settings.js +++ b/src/main/resources/webapp/interceptor-admin/js/settings.js @@ -60,7 +60,8 @@ function readSelectedHook() { onOk: (responseText) => { document.getElementById('hook-description-container').innerHTML = "Affected item type(s): " + Hooks.selectedHook.itemTypes.map(t => getItemTypeName(t)).join(", ") + "
" + - "Interceptor action type: " + getInterceptorTypeName(Hooks.selectedHook.actionType) + "
" + + "Interceptor action type: " + getInterceptorTypeName(Hooks.selectedHook.actionType) + "

" + + "Hook version: " + Hooks.selectedHook.version + "

" + Hooks.selectedHook.description; parseAndSetSettings(responseText, true); readAndFillRevisions();