1 /*
   2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 package jdk.test.lib.artifacts;
  25 
  26 import java.io.UncheckedIOException;
  27 import java.lang.reflect.Method;
  28 import java.net.MalformedURLException;
  29 import java.net.URL;
  30 import java.net.URLClassLoader;
  31 import java.nio.file.Files;
  32 import java.nio.file.Path;
  33 import java.nio.file.Paths;
  34 import java.util.HashMap;
  35 import java.util.Map;
  36 import java.util.stream.Stream;
  37 
  38 public class JibArtifactManager implements ArtifactManager {
  39     private static final String JIB_SERVICE_FACTORY = "com.oracle.jib.api.JibServiceFactory";
  40     public static final String JIB_HOME_ENV_NAME = "JIB_HOME";
  41     private static String jibVersion = "1.0";
  42 
  43     private Object installerObject;
  44     private ClassLoader classLoader;
  45 
  46     private JibArtifactManager(Object installerObject, ClassLoader classLoader) {
  47         this.installerObject = installerObject;
  48         this.classLoader = classLoader;
  49     }
  50 
  51     public static JibArtifactManager newInstance() throws ClassNotFoundException {
  52         Path jibInstallDir = Paths.get(System.getenv(JIB_HOME_ENV_NAME));
  53         Path libDir = jibInstallDir.resolve("lib");
  54         if (!Files.isDirectory(libDir)) {
  55             throw new ClassNotFoundException(JIB_SERVICE_FACTORY);
  56         }
  57         try {
  58             URL[] jarUrls;
  59             try (Stream<Path> files = Files.list(libDir)) {
  60                 jarUrls = files.filter(path -> path.toString().endsWith(".jar"))
  61                         .map(path -> {
  62                             try {
  63                                 return path.toUri().toURL();
  64                             } catch (MalformedURLException e) {
  65                                 throw new UncheckedIOException(e);
  66                             }
  67                         }).toArray(URL[]::new);
  68             }
  69             // Create a class loader using all those jars and set the parent to the
  70             // current class loader's parent.
  71             ClassLoader classLoader = new URLClassLoader(jarUrls, JibArtifactManager.class.getClassLoader().getParent());
  72 
  73             // Temporarily replace the context classLoader
  74             Thread currentThread = Thread.currentThread();
  75             ClassLoader oldContextLoader = currentThread.getContextClassLoader();
  76             currentThread.setContextClassLoader(classLoader);
  77 
  78             Class jibServiceFactory = classLoader.loadClass(JIB_SERVICE_FACTORY);
  79             try {
  80                 Object jibArtifactInstaller = jibServiceFactory.getMethod("createJibArtifactInstaller").invoke(null);
  81                 return new JibArtifactManager(jibArtifactInstaller, classLoader);
  82             } finally {
  83                 currentThread.setContextClassLoader(oldContextLoader);
  84             }
  85 
  86         } catch (Exception e) {
  87             throw new ClassNotFoundException(JIB_SERVICE_FACTORY, e);
  88         }
  89     }
  90 
  91     private Path download(String jibVersion, HashMap<String, Object> artifactDescription) throws Exception {
  92         return invokeInstallerMethod("download", jibVersion, artifactDescription);
  93     }
  94 
  95     private Path install(String jibVersion, HashMap<String, Object> artifactDescription) throws Exception {
  96         return invokeInstallerMethod("install", jibVersion, artifactDescription);
  97     }
  98 
  99     private Path invokeInstallerMethod(String methodName, String jibVersion,
 100                                        HashMap<String, Object> artifactDescription) throws Exception {
 101         // Temporarily replace the context classLoader
 102         Thread currentThread = Thread.currentThread();
 103         ClassLoader oldContextLoader = currentThread.getContextClassLoader();
 104         currentThread.setContextClassLoader(classLoader);
 105         try {
 106             Method m = classLoader.loadClass("com.oracle.jib.api.JibArtifactInstaller")
 107                     .getMethod(methodName, String.class, Map.class);
 108             return (Path) m.invoke(installerObject, jibVersion, artifactDescription);
 109         } finally {
 110             currentThread.setContextClassLoader(oldContextLoader);
 111         }
 112     }
 113 
 114     @Override
 115     public Path resolve(Artifact artifact) throws ArtifactResolverException {
 116         Path path;
 117         // Use the DefaultArtifactManager to enable users to override locations
 118         try {
 119             ArtifactManager manager = new DefaultArtifactManager();
 120             path = manager.resolve(artifact);
 121         } catch (ArtifactResolverException e) {
 122             // Location hasn't been overridden, continue to automatically try to resolve the dependency
 123             try {
 124                 HashMap<String, Object> artifactDescription = new HashMap<>();
 125                 artifactDescription.put("module", artifact.name());
 126                 artifactDescription.put("organization", artifact.organization());
 127                 artifactDescription.put("ext", artifact.extension());
 128                 artifactDescription.put("revision", artifact.revision());
 129                 if (artifact.classifier().length() > 0) {
 130                     artifactDescription.put("classifier", artifact.classifier());
 131                 }
 132 
 133                 path = download(jibVersion, artifactDescription);
 134                 if (artifact.unpack()) {
 135                     path = install(jibVersion, artifactDescription);
 136                 }
 137             } catch (Exception e2) {
 138                 throw new ArtifactResolverException("Failed to resolve the artifact " + artifact, e2);
 139             }
 140         }
 141         return path;
 142     }
 143 }