From 7d5d36c3525db3e50315fc69ddfebf641c052624 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Waldemar=20=C5=BBurowski?= <45210402+wzur-r3@users.noreply.github.com> Date: Fri, 17 Dec 2021 17:54:59 +0100 Subject: [PATCH 1/6] Update build.gradle (#6991) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 11054623fa..6ae4ddd339 100644 --- a/build.gradle +++ b/build.gradle @@ -68,7 +68,7 @@ buildscript { ext.servlet_version = '4.0.1' ext.assertj_version = '3.12.2' ext.slf4j_version = '1.7.26' - ext.log4j_version = '2.11.2' + ext.log4j_version = '2.16.0' ext.bouncycastle_version = constants.getProperty("bouncycastleVersion") ext.guava_version = constants.getProperty("guavaVersion") ext.caffeine_version = constants.getProperty("caffeineVersion") From db0e45146a8f4071c036a88c60fc37d4e10f0e57 Mon Sep 17 00:00:00 2001 From: Adel El-Beik <48713346+adelel1@users.noreply.github.com> Date: Tue, 21 Dec 2021 11:24:02 +0000 Subject: [PATCH 2/6] ENT-6494: Upgrade log4j to 2.17.0 (#6998) --- build.gradle | 2 +- .../common/logging/manifest/Manifests.java | 379 ++++++++++++++++++ .../net/corda/common/logging/CordaVersion.kt | 4 +- 3 files changed, 382 insertions(+), 3 deletions(-) create mode 100644 common/logging/src/main/java/net/corda/common/logging/manifest/Manifests.java diff --git a/build.gradle b/build.gradle index 6ae4ddd339..c183661636 100644 --- a/build.gradle +++ b/build.gradle @@ -68,7 +68,7 @@ buildscript { ext.servlet_version = '4.0.1' ext.assertj_version = '3.12.2' ext.slf4j_version = '1.7.26' - ext.log4j_version = '2.16.0' + ext.log4j_version = '2.17.0' ext.bouncycastle_version = constants.getProperty("bouncycastleVersion") ext.guava_version = constants.getProperty("guavaVersion") ext.caffeine_version = constants.getProperty("caffeineVersion") diff --git a/common/logging/src/main/java/net/corda/common/logging/manifest/Manifests.java b/common/logging/src/main/java/net/corda/common/logging/manifest/Manifests.java new file mode 100644 index 0000000000..efb9b98362 --- /dev/null +++ b/common/logging/src/main/java/net/corda/common/logging/manifest/Manifests.java @@ -0,0 +1,379 @@ +/** + * Copyright (c) 2012-2014, jcabi.com + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: 1) Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. 2) Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. 3) Neither the name of the jcabi.com nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT + * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.corda.common.logging.manifest; + +import com.jcabi.log.Logger; +import com.jcabi.manifests.ClasspathMfs; +import com.jcabi.manifests.MfMap; +import com.jcabi.manifests.Mfs; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.jar.Attributes; +import java.util.jar.Manifest; + +/** + * To a large effect this is a copy of {@code com.jcabi.manifests.Manifests} class + * with some fixes that are identified in the code with "FIX-UP" comment. + * + * Static reader of {@code META-INF/MANIFEST.MF} files. + * + * The class provides convenient methods to read + * all {@code MANIFEST.MF} files available in classpath + * and all attributes from them. + * + *

This mechanism may be very useful for transferring + * information from continuous integration environment to the production + * environment. For example, you want your site to show project version and + * the date of {@code WAR} file packaging. First, you configure + * {@code maven-war-plugin} to add this information to {@code MANIFEST.MF}: + * + *

 <plugin>
+ *  <artifactId>maven-war-plugin</artifactId>
+ *  <configuration>
+ *   <archive>
+ *    <manifestEntries>
+ *     <Foo-Version>${project.version}</Foo-Version>
+ *     <Foo-Date>${maven.build.timestamp}</Foo-Date>
+ *    </manifestEntries>
+ *   </archive>
+ *  </configuration>
+ * </plugin>
+ * + *

{@code maven-war-plugin} will add these attributes to your + * {@code MANIFEST.MF} file and the + * project will be deployed to the production environment. Then, you can read + * these attributes where it's necessary (in one of your JAXB annotated objects, + * for example) and show to users: + * + *

 import com.jcabi.manifests.Manifest;
+ * import java.text.SimpleDateFormat;
+ * import java.util.Date;
+ * import java.util.Locale;
+ * import javax.xml.bind.annotation.XmlElement;
+ * import javax.xml.bind.annotation.XmlRootElement;
+ * @XmlRootElement
+ * public final class Page {
+ *   @XmlElement
+ *   public String version() {
+ *     return Manifests.read("Foo-Version");
+ *   }
+ *   @XmlElement
+ *   public Date date() {
+ *     return new SimpleDateFormat("yyyy.MM.dd", Locale.ENGLISH).parse(
+ *       Manifests.read("Foo-Date");
+ *     );
+ *   }
+ * }
+ * + *

If you want to add more manifests to the collection, use + * its static instance: + * + *

Manifests.DEFAULT.append(new FilesMfs(new File("MANIFEST.MF")));
+ * + *

You can also modify the map directly: + * + *

Manifests.DEFAULT.put("Hello", "world");
+ * + *

The only dependency you need (check the latest version at + * jcabi-manifests): + * + *

 <dependency>
+ *  <groupId>com.jcabi</groupId>
+ *  <artifactId>jcabi-manifests</artifactId>
+ * </dependency>
+ * + * @author Yegor Bugayenko (yegor@tpc2.com) + * @version $Id$ + * @since 0.7 + * @see JAR Manifest + * @see Maven Archiver + * @see manifests.jcabi.com + * @see How to Read MANIFEST.MF Files + */ +@SuppressWarnings("PMD.TooManyMethods") +public final class Manifests implements MfMap { + + /** + * Default singleton. + */ + public static final MfMap DEFAULT = new Manifests(); + + /** + * Attributes retrieved. + */ + private final transient Map attributes; + + static { + try { + Manifests.DEFAULT.append(new ClasspathMfs()); + } catch (final IOException ex) { + // FIX-UP: Log exception correctly + Logger.error( + Manifests.class, + "#load(): '%s' failed %[exception]s", ex.getMessage(), ex + ); + } + } + + /** + * Public ctor. + * @since 1.0 + */ + public Manifests() { + this(new HashMap(0)); + } + + /** + * Public ctor. + * @param attrs Attributes to encapsulate + * @since 1.0 + */ + public Manifests(final Map attrs) { + super(); + this.attributes = new ConcurrentHashMap(attrs); + } + + @Override + public int size() { + return this.attributes.size(); + } + + @Override + public boolean isEmpty() { + return this.attributes.isEmpty(); + } + + @Override + public boolean containsKey(final Object key) { + return this.attributes.containsKey(key); + } + + @Override + public boolean containsValue(final Object value) { + return this.attributes.containsValue(value); + } + + @Override + public String get(final Object key) { + return this.attributes.get(key); + } + + @Override + public String put(final String key, final String value) { + return this.attributes.put(key, value); + } + + @Override + public String remove(final Object key) { + return this.attributes.remove(key); + } + + @Override + public void putAll(final Map attrs) { + this.attributes.putAll(attrs); + } + + @Override + public void clear() { + this.attributes.clear(); + } + + @Override + public Set keySet() { + return this.attributes.keySet(); + } + + @Override + public Collection values() { + return this.attributes.values(); + } + + @Override + public Set> entrySet() { + return this.attributes.entrySet(); + } + + @Override + public MfMap append(final Mfs streams) throws IOException { + final long start = System.currentTimeMillis(); + final Collection list = streams.fetch(); + int saved = 0; + int ignored = 0; + for (final InputStream stream : list) { + for (final Map.Entry attr + : Manifests.load(stream).entrySet()) { + if (this.attributes.containsKey(attr.getKey())) { + ++ignored; + } else { + this.attributes.put(attr.getKey(), attr.getValue()); + ++saved; + } + } + } + Logger.info( + this, + // @checkstyle LineLength (1 line) + "%d attributes loaded from %d stream(s) in %[ms]s, %d saved, %d ignored: %[list]s", + this.attributes.size(), list.size(), + System.currentTimeMillis() - start, + saved, ignored, + new TreeSet(this.attributes.keySet()) + ); + return this; + } + + /** + * Read one attribute available in one of {@code MANIFEST.MF} files. + * + *

If such a attribute doesn't exist {@link IllegalArgumentException} + * will be thrown. If you're not sure whether the attribute is present or + * not use {@link #exists(String)} beforehand. + * + *

The method is thread-safe. + * + * @param name Name of the attribute + * @return The value of the attribute retrieved + */ + public static String read(final String name) { + if (name == null) { + throw new IllegalArgumentException("attribute can't be NULL"); + } + if (name.isEmpty()) { + throw new IllegalArgumentException("attribute can't be empty"); + } + if (!Manifests.exists(name)) { + throw new IllegalArgumentException( + Logger.format( + // @checkstyle LineLength (1 line) + "Attribute '%s' not found in MANIFEST.MF file(s) among %d other attribute(s): %[list]s", + name, + Manifests.DEFAULT.size(), + new TreeSet(Manifests.DEFAULT.keySet()) + ) + ); + } + return Manifests.DEFAULT.get(name); + } + + /** + * Check whether attribute exists in any of {@code MANIFEST.MF} files. + * + *

Use this method before {@link #read(String)} to check whether an + * attribute exists, in order to avoid a runtime exception. + * + *

The method is thread-safe. + * + * @param name Name of the attribute to check + * @return Returns {@code TRUE} if it exists, {@code FALSE} otherwise + */ + public static boolean exists(final String name) { + if (name == null) { + throw new IllegalArgumentException("attribute name can't be NULL"); + } + if (name.isEmpty()) { + throw new IllegalArgumentException("attribute name can't be empty"); + } + return Manifests.DEFAULT.containsKey(name); + } + + /** + * Load attributes from input stream. + * + *

Inside the method we catch {@code RuntimeException} (which may look + * suspicious) in order to protect our execution flow from expected (!) + * exceptions from {@link Manifest#getMainAttributes()}. For some reason, + * this JDK method doesn't throw checked exceptions if {@code MANIFEST.MF} + * file format is broken. Instead, it throws a runtime exception (an + * unchecked one), which we should catch in such an inconvenient way. + * + * @param stream Stream to load from + * @return The attributes loaded + * @throws IOException If some problem happens + * @since 0.8 + */ + @SuppressWarnings("PMD.AvoidCatchingGenericException") + private static Map load(final InputStream stream) + throws IOException { + final ConcurrentMap props = + new ConcurrentHashMap(0); + try { + final Manifest manifest = new Manifest(stream); + final Attributes attrs = manifest.getMainAttributes(); + for (final Object key : attrs.keySet()) { + final String value = attrs.getValue( + Attributes.Name.class.cast(key) + ); + props.put(key.toString(), value); + } + /* + * FIXUP: Logging statement below is harmful and may result in Inputstreams returned + * by `feed()` method to be closed. + * This will result in the following exception: + * [ERROR] 10:55:15+0000 [main] manifest.Manifests. - #load(): 'Stream closed' failed java.io.IOException: Stream closed + at java.util.zip.InflaterInputStream.ensureOpen(Unknown Source) + at java.util.zip.InflaterInputStream.read(Unknown Source) + at java.io.FilterInputStream.read(Unknown Source) + at java.util.jar.Manifest$FastInputStream.fill(Unknown Source) + at java.util.jar.Manifest$FastInputStream.readLine(Unknown Source) + at java.util.jar.Manifest$FastInputStream.readLine(Unknown Source) + at java.util.jar.Attributes.read(Unknown Source) + at java.util.jar.Manifest.read(Unknown Source) + at java.util.jar.Manifest.(Unknown Source) + at java.util.jar.Manifest.(Unknown Source) + ... + + * Initial investigation shows that this might be related to the order of manifest + * entries discovered in the classpath. + * Also discovered some related changes in the original library: https://github.com/jcabi/jcabi-manifests/pull/43 + * But those were never officially released as a new version. + */ + /* Logger.debug( + Manifests.class, + "%d attribute(s) loaded %[list]s", + props.size(), new TreeSet(props.keySet()) + );*/ + // @checkstyle IllegalCatch (1 line) + } catch (final RuntimeException ex) { + Logger.error(Manifests.class, "#load(): failed %[exception]s", ex); + } finally { + stream.close(); + } + return props; + } + +} diff --git a/common/logging/src/main/kotlin/net/corda/common/logging/CordaVersion.kt b/common/logging/src/main/kotlin/net/corda/common/logging/CordaVersion.kt index 083f0a078a..e1b46c154b 100644 --- a/common/logging/src/main/kotlin/net/corda/common/logging/CordaVersion.kt +++ b/common/logging/src/main/kotlin/net/corda/common/logging/CordaVersion.kt @@ -1,6 +1,6 @@ package net.corda.common.logging -import com.jcabi.manifests.Manifests +import net.corda.common.logging.manifest.Manifests class CordaVersion { companion object { @@ -24,4 +24,4 @@ class CordaVersion { arrayOf("No version data is available in the MANIFEST file.") } } -} \ No newline at end of file +} From 9a7308f9543306db1bb28f503248056237c05f43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Waldemar=20=C5=BBurowski?= <45210402+wzur-r3@users.noreply.github.com> Date: Tue, 4 Jan 2022 11:50:24 +0100 Subject: [PATCH 3/6] NOTICK: allow to skip executing all tests for a release (#7001) * backported from emergency releases for log4j updates * adds a build parameter, which control if tests should be run or not, default is `true` --- .ci/dev/regression/Jenkinsfile | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/.ci/dev/regression/Jenkinsfile b/.ci/dev/regression/Jenkinsfile index fb6e3896ff..13ef2be4c2 100644 --- a/.ci/dev/regression/Jenkinsfile +++ b/.ci/dev/regression/Jenkinsfile @@ -65,6 +65,7 @@ pipeline { parameters { choice choices: nexusIqStageChoices, description: 'NexusIQ stage for code evaluation', name: 'nexusIqStage' + booleanParam defaultValue: true, description: 'Run tests during this build?', name: 'DO_TEST' } /* @@ -91,6 +92,9 @@ pipeline { } stage('Stash') { + when { + expression { params.DO_TEST } + } steps { stash name: 'compiled', useDefaultExcludes: false } @@ -115,6 +119,10 @@ pipeline { } stage('All Tests') { + when { + expression { params.DO_TEST } + beforeAgent true + } parallel { stage('Another agent') { agent { @@ -297,10 +305,12 @@ pipeline { always { script { try { - unstash 'allure-input' - allure includeProperties: false, - jdk: '', - results: [[path: '**/allure-input']] + if (params.DO_TEST) { + unstash 'allure-input' + allure includeProperties: false, + jdk: '', + results: [[path: '**/allure-input']] + } } catch (err) { echo("Allure report generation failed: $err") From 0d8f5fb96523ecdbbf83582f7c8461fb5ddbb6bd Mon Sep 17 00:00:00 2001 From: Waldemar Zurowski Date: Wed, 5 Jan 2022 15:22:50 +0100 Subject: [PATCH 4/6] Updated classgraph version --- constants.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/constants.properties b/constants.properties index 2ed3714aec..1e69b8fac9 100644 --- a/constants.properties +++ b/constants.properties @@ -21,7 +21,7 @@ quasarVersion11=0.8.0_r3 jdkClassifier11=jdk11 proguardVersion=6.1.1 bouncycastleVersion=1.66 -classgraphVersion=4.8.78 +classgraphVersion=4.8.90 disruptorVersion=3.4.2 typesafeConfigVersion=1.3.4 jsr305Version=3.0.2 From 0751bfd835ea8499e25a8bdf53b2ca50c7a043d1 Mon Sep 17 00:00:00 2001 From: Waldemar Zurowski Date: Wed, 5 Jan 2022 15:35:30 +0100 Subject: [PATCH 5/6] Revert "Updated classgraph version" This reverts commit 0d8f5fb96523ecdbbf83582f7c8461fb5ddbb6bd. --- constants.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/constants.properties b/constants.properties index 1e69b8fac9..2ed3714aec 100644 --- a/constants.properties +++ b/constants.properties @@ -21,7 +21,7 @@ quasarVersion11=0.8.0_r3 jdkClassifier11=jdk11 proguardVersion=6.1.1 bouncycastleVersion=1.66 -classgraphVersion=4.8.90 +classgraphVersion=4.8.78 disruptorVersion=3.4.2 typesafeConfigVersion=1.3.4 jsr305Version=3.0.2 From d3494f8a84588374436369cda78f4d83f0f9e307 Mon Sep 17 00:00:00 2001 From: Adel El-Beik <48713346+adelel1@users.noreply.github.com> Date: Tue, 21 Dec 2021 11:24:02 +0000 Subject: [PATCH 6/6] Revert "ENT-6494: Upgrade log4j to 2.17.0 (#6998)" This reverts commit db0e45146a8f4071c036a88c60fc37d4e10f0e57. # Conflicts: # build.gradle --- .../common/logging/manifest/Manifests.java | 379 ------------------ .../net/corda/common/logging/CordaVersion.kt | 4 +- 2 files changed, 2 insertions(+), 381 deletions(-) delete mode 100644 common/logging/src/main/java/net/corda/common/logging/manifest/Manifests.java diff --git a/common/logging/src/main/java/net/corda/common/logging/manifest/Manifests.java b/common/logging/src/main/java/net/corda/common/logging/manifest/Manifests.java deleted file mode 100644 index efb9b98362..0000000000 --- a/common/logging/src/main/java/net/corda/common/logging/manifest/Manifests.java +++ /dev/null @@ -1,379 +0,0 @@ -/** - * Copyright (c) 2012-2014, jcabi.com - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: 1) Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. 2) Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. 3) Neither the name of the jcabi.com nor - * the names of its contributors may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT - * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.corda.common.logging.manifest; - -import com.jcabi.log.Logger; -import com.jcabi.manifests.ClasspathMfs; -import com.jcabi.manifests.MfMap; -import com.jcabi.manifests.Mfs; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.jar.Attributes; -import java.util.jar.Manifest; - -/** - * To a large effect this is a copy of {@code com.jcabi.manifests.Manifests} class - * with some fixes that are identified in the code with "FIX-UP" comment. - * - * Static reader of {@code META-INF/MANIFEST.MF} files. - * - * The class provides convenient methods to read - * all {@code MANIFEST.MF} files available in classpath - * and all attributes from them. - * - *

This mechanism may be very useful for transferring - * information from continuous integration environment to the production - * environment. For example, you want your site to show project version and - * the date of {@code WAR} file packaging. First, you configure - * {@code maven-war-plugin} to add this information to {@code MANIFEST.MF}: - * - *

 <plugin>
- *  <artifactId>maven-war-plugin</artifactId>
- *  <configuration>
- *   <archive>
- *    <manifestEntries>
- *     <Foo-Version>${project.version}</Foo-Version>
- *     <Foo-Date>${maven.build.timestamp}</Foo-Date>
- *    </manifestEntries>
- *   </archive>
- *  </configuration>
- * </plugin>
- * - *

{@code maven-war-plugin} will add these attributes to your - * {@code MANIFEST.MF} file and the - * project will be deployed to the production environment. Then, you can read - * these attributes where it's necessary (in one of your JAXB annotated objects, - * for example) and show to users: - * - *

 import com.jcabi.manifests.Manifest;
- * import java.text.SimpleDateFormat;
- * import java.util.Date;
- * import java.util.Locale;
- * import javax.xml.bind.annotation.XmlElement;
- * import javax.xml.bind.annotation.XmlRootElement;
- * @XmlRootElement
- * public final class Page {
- *   @XmlElement
- *   public String version() {
- *     return Manifests.read("Foo-Version");
- *   }
- *   @XmlElement
- *   public Date date() {
- *     return new SimpleDateFormat("yyyy.MM.dd", Locale.ENGLISH).parse(
- *       Manifests.read("Foo-Date");
- *     );
- *   }
- * }
- * - *

If you want to add more manifests to the collection, use - * its static instance: - * - *

Manifests.DEFAULT.append(new FilesMfs(new File("MANIFEST.MF")));
- * - *

You can also modify the map directly: - * - *

Manifests.DEFAULT.put("Hello", "world");
- * - *

The only dependency you need (check the latest version at - * jcabi-manifests): - * - *

 <dependency>
- *  <groupId>com.jcabi</groupId>
- *  <artifactId>jcabi-manifests</artifactId>
- * </dependency>
- * - * @author Yegor Bugayenko (yegor@tpc2.com) - * @version $Id$ - * @since 0.7 - * @see JAR Manifest - * @see Maven Archiver - * @see manifests.jcabi.com - * @see How to Read MANIFEST.MF Files - */ -@SuppressWarnings("PMD.TooManyMethods") -public final class Manifests implements MfMap { - - /** - * Default singleton. - */ - public static final MfMap DEFAULT = new Manifests(); - - /** - * Attributes retrieved. - */ - private final transient Map attributes; - - static { - try { - Manifests.DEFAULT.append(new ClasspathMfs()); - } catch (final IOException ex) { - // FIX-UP: Log exception correctly - Logger.error( - Manifests.class, - "#load(): '%s' failed %[exception]s", ex.getMessage(), ex - ); - } - } - - /** - * Public ctor. - * @since 1.0 - */ - public Manifests() { - this(new HashMap(0)); - } - - /** - * Public ctor. - * @param attrs Attributes to encapsulate - * @since 1.0 - */ - public Manifests(final Map attrs) { - super(); - this.attributes = new ConcurrentHashMap(attrs); - } - - @Override - public int size() { - return this.attributes.size(); - } - - @Override - public boolean isEmpty() { - return this.attributes.isEmpty(); - } - - @Override - public boolean containsKey(final Object key) { - return this.attributes.containsKey(key); - } - - @Override - public boolean containsValue(final Object value) { - return this.attributes.containsValue(value); - } - - @Override - public String get(final Object key) { - return this.attributes.get(key); - } - - @Override - public String put(final String key, final String value) { - return this.attributes.put(key, value); - } - - @Override - public String remove(final Object key) { - return this.attributes.remove(key); - } - - @Override - public void putAll(final Map attrs) { - this.attributes.putAll(attrs); - } - - @Override - public void clear() { - this.attributes.clear(); - } - - @Override - public Set keySet() { - return this.attributes.keySet(); - } - - @Override - public Collection values() { - return this.attributes.values(); - } - - @Override - public Set> entrySet() { - return this.attributes.entrySet(); - } - - @Override - public MfMap append(final Mfs streams) throws IOException { - final long start = System.currentTimeMillis(); - final Collection list = streams.fetch(); - int saved = 0; - int ignored = 0; - for (final InputStream stream : list) { - for (final Map.Entry attr - : Manifests.load(stream).entrySet()) { - if (this.attributes.containsKey(attr.getKey())) { - ++ignored; - } else { - this.attributes.put(attr.getKey(), attr.getValue()); - ++saved; - } - } - } - Logger.info( - this, - // @checkstyle LineLength (1 line) - "%d attributes loaded from %d stream(s) in %[ms]s, %d saved, %d ignored: %[list]s", - this.attributes.size(), list.size(), - System.currentTimeMillis() - start, - saved, ignored, - new TreeSet(this.attributes.keySet()) - ); - return this; - } - - /** - * Read one attribute available in one of {@code MANIFEST.MF} files. - * - *

If such a attribute doesn't exist {@link IllegalArgumentException} - * will be thrown. If you're not sure whether the attribute is present or - * not use {@link #exists(String)} beforehand. - * - *

The method is thread-safe. - * - * @param name Name of the attribute - * @return The value of the attribute retrieved - */ - public static String read(final String name) { - if (name == null) { - throw new IllegalArgumentException("attribute can't be NULL"); - } - if (name.isEmpty()) { - throw new IllegalArgumentException("attribute can't be empty"); - } - if (!Manifests.exists(name)) { - throw new IllegalArgumentException( - Logger.format( - // @checkstyle LineLength (1 line) - "Attribute '%s' not found in MANIFEST.MF file(s) among %d other attribute(s): %[list]s", - name, - Manifests.DEFAULT.size(), - new TreeSet(Manifests.DEFAULT.keySet()) - ) - ); - } - return Manifests.DEFAULT.get(name); - } - - /** - * Check whether attribute exists in any of {@code MANIFEST.MF} files. - * - *

Use this method before {@link #read(String)} to check whether an - * attribute exists, in order to avoid a runtime exception. - * - *

The method is thread-safe. - * - * @param name Name of the attribute to check - * @return Returns {@code TRUE} if it exists, {@code FALSE} otherwise - */ - public static boolean exists(final String name) { - if (name == null) { - throw new IllegalArgumentException("attribute name can't be NULL"); - } - if (name.isEmpty()) { - throw new IllegalArgumentException("attribute name can't be empty"); - } - return Manifests.DEFAULT.containsKey(name); - } - - /** - * Load attributes from input stream. - * - *

Inside the method we catch {@code RuntimeException} (which may look - * suspicious) in order to protect our execution flow from expected (!) - * exceptions from {@link Manifest#getMainAttributes()}. For some reason, - * this JDK method doesn't throw checked exceptions if {@code MANIFEST.MF} - * file format is broken. Instead, it throws a runtime exception (an - * unchecked one), which we should catch in such an inconvenient way. - * - * @param stream Stream to load from - * @return The attributes loaded - * @throws IOException If some problem happens - * @since 0.8 - */ - @SuppressWarnings("PMD.AvoidCatchingGenericException") - private static Map load(final InputStream stream) - throws IOException { - final ConcurrentMap props = - new ConcurrentHashMap(0); - try { - final Manifest manifest = new Manifest(stream); - final Attributes attrs = manifest.getMainAttributes(); - for (final Object key : attrs.keySet()) { - final String value = attrs.getValue( - Attributes.Name.class.cast(key) - ); - props.put(key.toString(), value); - } - /* - * FIXUP: Logging statement below is harmful and may result in Inputstreams returned - * by `feed()` method to be closed. - * This will result in the following exception: - * [ERROR] 10:55:15+0000 [main] manifest.Manifests. - #load(): 'Stream closed' failed java.io.IOException: Stream closed - at java.util.zip.InflaterInputStream.ensureOpen(Unknown Source) - at java.util.zip.InflaterInputStream.read(Unknown Source) - at java.io.FilterInputStream.read(Unknown Source) - at java.util.jar.Manifest$FastInputStream.fill(Unknown Source) - at java.util.jar.Manifest$FastInputStream.readLine(Unknown Source) - at java.util.jar.Manifest$FastInputStream.readLine(Unknown Source) - at java.util.jar.Attributes.read(Unknown Source) - at java.util.jar.Manifest.read(Unknown Source) - at java.util.jar.Manifest.(Unknown Source) - at java.util.jar.Manifest.(Unknown Source) - ... - - * Initial investigation shows that this might be related to the order of manifest - * entries discovered in the classpath. - * Also discovered some related changes in the original library: https://github.com/jcabi/jcabi-manifests/pull/43 - * But those were never officially released as a new version. - */ - /* Logger.debug( - Manifests.class, - "%d attribute(s) loaded %[list]s", - props.size(), new TreeSet(props.keySet()) - );*/ - // @checkstyle IllegalCatch (1 line) - } catch (final RuntimeException ex) { - Logger.error(Manifests.class, "#load(): failed %[exception]s", ex); - } finally { - stream.close(); - } - return props; - } - -} diff --git a/common/logging/src/main/kotlin/net/corda/common/logging/CordaVersion.kt b/common/logging/src/main/kotlin/net/corda/common/logging/CordaVersion.kt index e1b46c154b..083f0a078a 100644 --- a/common/logging/src/main/kotlin/net/corda/common/logging/CordaVersion.kt +++ b/common/logging/src/main/kotlin/net/corda/common/logging/CordaVersion.kt @@ -1,6 +1,6 @@ package net.corda.common.logging -import net.corda.common.logging.manifest.Manifests +import com.jcabi.manifests.Manifests class CordaVersion { companion object { @@ -24,4 +24,4 @@ class CordaVersion { arrayOf("No version data is available in the MANIFEST file.") } } -} +} \ No newline at end of file