package org.infinispan.commons.util.uberjar; import java.io.IOException; import java.io.InputStream; import java.lang.invoke.MethodHandles; import java.net.URL; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.function.Predicate; import java.util.jar.Manifest; import org.infinispan.commons.logging.Log; import org.infinispan.commons.logging.LogFactory; /** * Manifest based implementation of a {@link UberJarDuplicatedJarsWarner}. * <p> * Incorrect combinations: * <ul> * <li>Commons + any of the Uber Jars</li> * <li>Embedded + Remote Uber Jar</li> * <li>Commons + Embedded + Remote Uber Jar</li> * </ul> * </p> * * @author slaskawi */ public class ManifestUberJarDuplicatedJarsWarner implements UberJarDuplicatedJarsWarner { private static final Log logger = LogFactory.getLog(MethodHandles.lookup().lookupClass()); private static final String MANIFEST_LOCATION = "META-INF/MANIFEST.MF"; private final String SYMBOLIC_NAME_MANIFEST_ENTRY = "Bundle-SymbolicName"; @Override public boolean isClasspathCorrect() { List<String> bundleNames = getBundleSymbolicNames(); long numberOfMatches = bundleNames.stream() .filter(hasRemoteUberJar() .or(hasEmbeddedUberJar()) .or(hasCommons())) .count(); return numberOfMatches < 2; } List<String> getBundleSymbolicNames() { List<String> symbolicNames = new ArrayList<>(); try { Enumeration<URL> resources = getClass().getClassLoader().getResources(MANIFEST_LOCATION); while (resources.hasMoreElements()) { URL manifestUrl = resources.nextElement(); try (InputStream is = manifestUrl.openStream()) { Manifest manifest = new Manifest(is); symbolicNames.add(manifest.getMainAttributes().getValue(SYMBOLIC_NAME_MANIFEST_ENTRY)); } } } catch (IOException e) { logger.warn("Can not extract jar manifest from the classpath. Uber Jar classpath check is skipped."); } return symbolicNames; } Predicate<String> hasCommons() { return jarSymbolicName -> "org.infinispan.commons".equals(jarSymbolicName); } Predicate<String> hasEmbeddedUberJar() { return jarSymbolicName -> "org.infinispan.embedded".equals(jarSymbolicName); } Predicate<String> hasRemoteUberJar() { return jarSymbolicName -> "org.infinispan.remote".equals(jarSymbolicName); } @Override public CompletableFuture<Boolean> isClasspathCorrectAsync() { return CompletableFuture.supplyAsync(() -> isClasspathCorrect()); } }