| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.s4.base.util; |
| |
| import java.io.File; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| import java.util.ArrayList; |
| import java.util.Enumeration; |
| import java.util.List; |
| import java.util.jar.JarEntry; |
| import java.util.jar.JarFile; |
| |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import com.google.common.io.ByteStreams; |
| import com.google.common.io.Closeables; |
| import com.google.common.io.Files; |
| import com.google.inject.Inject; |
| import com.google.inject.name.Named; |
| |
| /** |
| * Helper class for creating S4RLoader instances for a given S4R file. |
| * |
| */ |
| public class S4RLoaderFactory { |
| |
| private static Logger logger = LoggerFactory.getLogger(S4RLoaderFactory.class); |
| |
| @Inject(optional = true) |
| @Named("s4.tmp.dir") |
| File tmpDir; |
| |
| /** |
| * Explodes the s4r archive in a subdirectory of a user specified directory through "s4.tmp.dir" parameter, and |
| * prepares a classloader that will load classes and resources from, first, the application classes, then the |
| * dependencies. |
| * |
| * Uses a temporary directory if s4.tmp.dir is not provided. |
| * |
| * Inspired from Hadoop's application classloading implementation (RunJar class). |
| * |
| * @param s4rPath |
| * path to s4r |
| * @return classloader that loads resources from the s4r in a predefined order |
| */ |
| public S4RLoader createS4RLoader(String s4rPath) { |
| File s4rDir = null; |
| if (tmpDir == null) { |
| s4rDir = Files.createTempDir(); |
| s4rDir.deleteOnExit(); |
| logger.warn( |
| "s4.tmp.dir not specified, using temporary directory [{}] for unpacking S4R. You may want to specify a parent non-temporary directory.", |
| s4rDir.getAbsolutePath()); |
| } else { |
| s4rDir = new File(tmpDir, s4rPath.substring(s4rPath.lastIndexOf(File.separator)) + "-" |
| + System.currentTimeMillis()); |
| if (!s4rDir.mkdir()) { |
| throw new RuntimeException("Cannot create directory for unzipping S4R file in [" |
| + s4rDir.getAbsolutePath() + "]. Aborting deployment."); |
| } |
| } |
| logger.info("Unzipping S4R archive in [{}]", s4rDir.getAbsolutePath()); |
| |
| JarFile jar = null; |
| try { |
| jar = new JarFile(s4rPath); |
| Enumeration<JarEntry> entries = jar.entries(); |
| while (entries.hasMoreElements()) { |
| JarEntry entry = entries.nextElement(); |
| if (!entry.isDirectory()) { |
| File to = new File(s4rDir, entry.getName()); |
| Files.createParentDirs(to); |
| InputStream is = jar.getInputStream(entry); |
| OutputStream os = new FileOutputStream(to); |
| try { |
| ByteStreams.copy(is, os); |
| } finally { |
| Closeables.closeQuietly(is); |
| Closeables.closeQuietly(os); |
| } |
| } |
| } |
| |
| List<URL> classpath = new ArrayList<URL>(); |
| addDirLibsToClassPath(classpath, s4rDir, "/app"); |
| addDirLibsToClassPath(classpath, s4rDir, "/lib"); |
| |
| S4RLoader s4rLoader = new S4RLoader(classpath.toArray(new URL[] {})); |
| return s4rLoader; |
| |
| } catch (IOException e) { |
| logger.error("Cannot process S4R [{}]: {}", s4rPath, e.getClass().getName() + "/" + e.getMessage()); |
| throw new RuntimeException("Cannot create S4R classloader", e); |
| } |
| } |
| |
| private void addDirLibsToClassPath(List<URL> classpath, File s4rDir, String dir) throws MalformedURLException { |
| File[] libs = new File(s4rDir, dir).listFiles(); |
| if (libs != null) { |
| for (int i = 0; i < libs.length; i++) { |
| if (!libs[i].isDirectory()) { |
| classpath.add(libs[i].toURI().toURL()); |
| } |
| } |
| } |
| } |
| } |