/* * 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.karaf.wrapper.internal; import org.apache.karaf.shell.support.ansi.SimpleAnsi; import org.apache.karaf.wrapper.WrapperService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.*; import java.util.HashMap; import java.util.Map; import java.util.Scanner; import java.util.jar.JarOutputStream; import java.util.zip.ZipEntry; /** * Default implementation of the wrapper service. */ public class WrapperServiceImpl implements WrapperService { private final static Logger LOGGER = LoggerFactory.getLogger(WrapperServiceImpl.class); public void install() throws Exception { install("karaf", "karaf", "", "AUTO_START"); } public File[] install(String name, String displayName, String description, String startType, String[] envs, String[] includes) throws Exception { File base = new File(System.getProperty("karaf.base")); File etc = new File(System.getProperty("karaf.etc")); File bin = new File(base, "bin"); File lib = new File(base, "lib/wrapper"); if (name == null) { name = base.getName(); } HashMap<String, String> props = new HashMap<>(); props.put("${java.home}", System.getenv("JAVA_HOME")); props.put("${karaf.home}", System.getProperty("karaf.home")); props.put("${karaf.base}", base.getPath()); props.put("${karaf.data}", System.getProperty("karaf.data")); props.put("${karaf.etc}", System.getProperty("karaf.etc")); props.put("${name}", name); props.put("${displayName}", displayName); props.put("${description}", description); props.put("${startType}", startType); String os = System.getProperty("os.name", "Unknown"); File serviceFile; File wrapperConf; File systemdFile = null; if (os.startsWith("Win")) { String arch = System.getProperty("os.arch"); if (arch.equalsIgnoreCase("amd64") || arch.equalsIgnoreCase("x86_64")) { mkdir(bin); copyResourceTo(new File(bin, name + "-wrapper.exe"), "windows64/karaf-wrapper.exe", false); serviceFile = new File(bin, name + "-service.bat"); wrapperConf = new File(etc, name + "-wrapper.conf"); copyFilteredResourceTo(wrapperConf, "windows64/karaf-wrapper.conf", props, envs, includes); copyFilteredResourceTo(serviceFile, "windows64/karaf-service.bat", props, envs, includes); mkdir(lib); copyResourceTo(new File(lib, "wrapper.dll"), "windows64/wrapper.dll", false); } else { mkdir(bin); copyResourceTo(new File(bin, name + "-wrapper.exe"), "windows/karaf-wrapper.exe", false); serviceFile = new File(bin, name + "-service.bat"); wrapperConf = new File(etc, name + "-wrapper.conf"); copyFilteredResourceTo(wrapperConf, "windows/karaf-wrapper.conf", props, envs, includes); copyFilteredResourceTo(serviceFile, "windows/karaf-service.bat", props, envs, includes); mkdir(lib); copyResourceTo(new File(lib, "wrapper.dll"), "windows/wrapper.dll", false); } } else if (os.startsWith("Mac OS X")) { mkdir(bin); File file = new File(bin, name + "-wrapper"); copyResourceTo(file, "macosx/karaf-wrapper", false); chmod(file, "a+x"); serviceFile = new File(bin, name + "-service"); copyFilteredResourceTo(serviceFile, "unix/karaf-service", props, envs, includes); chmod(serviceFile, "a+x"); wrapperConf = new File(etc, name + "-wrapper.conf"); copyFilteredResourceTo(wrapperConf, "unix/karaf-wrapper.conf", props, envs, includes); File plistConf = new File(bin, "org.apache.karaf."+ name + ".plist"); copyFilteredResourceTo(plistConf, "macosx/org.apache.karaf.KARAF.plist", props, envs, includes); mkdir(lib); copyResourceTo(new File(lib, "libwrapper.jnilib"), "macosx/libwrapper.jnilib", false); } else if (os.startsWith("Linux")) { String arch = System.getProperty("os.arch"); if (arch.equalsIgnoreCase("amd64") || arch.equalsIgnoreCase("x86_64")) { mkdir(bin); File file = new File(bin, name + "-wrapper"); copyResourceTo(file, "linux64/karaf-wrapper", false); chmod(file, "a+x"); serviceFile = new File(bin, name + "-service"); copyFilteredResourceTo(serviceFile, "unix/karaf-service", props, envs, includes); chmod(serviceFile, "a+x"); systemdFile = new File(bin, name + ".service"); copyFilteredResourceTo(systemdFile, "unix/karaf.service", props, envs, includes); chmod(systemdFile, "a+x"); wrapperConf = new File(etc, name + "-wrapper.conf"); copyFilteredResourceTo(wrapperConf, "unix/karaf-wrapper.conf", props, envs, includes); mkdir(lib); copyResourceTo(new File(lib, "libwrapper.so"), "linux64/libwrapper.so", false); } else { mkdir(bin); File file = new File(bin, name + "-wrapper"); copyResourceTo(file, "linux/karaf-wrapper", false); chmod(file, "a+x"); serviceFile = new File(bin, name + "-service"); copyFilteredResourceTo(serviceFile, "unix/karaf-service", props, envs, includes); chmod(serviceFile, "a+x"); systemdFile = new File(bin, name + ".service"); copyFilteredResourceTo(systemdFile, "unix/karaf.service", props, envs, includes); chmod(systemdFile, "a+x"); wrapperConf = new File(etc, name + "-wrapper.conf"); copyFilteredResourceTo(wrapperConf, "unix/karaf-wrapper.conf", props, envs, includes); mkdir(lib); copyResourceTo(new File(lib, "libwrapper.so"), "linux/libwrapper.so", false); } } else if (os.startsWith("AIX")) { String arch = System.getProperty("os.arch"); if (arch.equalsIgnoreCase("ppc64")) { mkdir(bin); File file = new File(bin, name + "-wrapper"); copyResourceTo(file, "aix/ppc64/karaf-wrapper", false); chmod(file, "a+x"); serviceFile = new File(bin, name + "-service"); copyFilteredResourceTo(serviceFile, "unix/karaf-service", props, envs, includes); chmod(serviceFile, "a+x"); wrapperConf = new File(etc, name + "-wrapper.conf"); copyFilteredResourceTo(wrapperConf, "unix/karaf-wrapper.conf", props, envs, includes); mkdir(lib); copyResourceTo(new File(lib, "libwrapper.a"), "aix/ppc64/libwrapper.a", false); } else { mkdir(bin); File file = new File(bin, name + "-wrapper"); copyResourceTo(file, "aix/ppc32/karaf-wrapper", false); chmod(file, "a+x"); serviceFile = new File(bin, name + "-service"); copyFilteredResourceTo(serviceFile, "unix/karaf-service", props, envs, includes); chmod(serviceFile, "a+x"); wrapperConf = new File(etc, name + "-wrapper.conf"); copyFilteredResourceTo(wrapperConf, "unix/karaf-wrapper.conf", props, envs, includes); mkdir(lib); copyResourceTo(new File(lib, "libwrapper.a"), "aix/ppc32/libwrapper.a", false); } } else if (os.startsWith("Solaris") || os.startsWith("SunOS")) { String arch = System.getProperty("os.arch"); if (arch.equalsIgnoreCase("sparc")) { mkdir(bin); File file = new File(bin, name + "-wrapper"); copyResourceTo(file, "solaris/sparc64/karaf-wrapper", false); chmod(file, "a+x"); serviceFile = new File(bin, name + "-service"); copyFilteredResourceTo(serviceFile, "unix/karaf-service", props, envs, includes); chmod(serviceFile, "a+x"); wrapperConf = new File(etc, name + "-wrapper.conf"); copyFilteredResourceTo(wrapperConf, "unix/karaf-wrapper.conf", props, envs, includes); mkdir(lib); copyResourceTo(new File(lib, "libwrapper.so"), "solaris/sparc64/libwrapper.so", false); } else if (arch.equalsIgnoreCase("x86")) { mkdir(bin); File file = new File(bin, name + "-wrapper"); copyResourceTo(file, "solaris/x86/karaf-wrapper", false); chmod(file, "a+x"); serviceFile = new File(bin, name + "-service"); copyFilteredResourceTo(serviceFile, "unix/karaf-service", props, envs, includes); chmod(serviceFile, "a+x"); wrapperConf = new File(etc, name + "-wrapper.conf"); copyFilteredResourceTo(wrapperConf, "unix/karaf-wrapper.conf", props, envs, includes); mkdir(lib); copyResourceTo(new File(lib, "libwrapper.so"), "solaris/x86/libwrapper.so", false); } else if (arch.equalsIgnoreCase("amd64") || arch.equalsIgnoreCase("x86_64")) { mkdir(bin); File file = new File(bin, name + "-wrapper"); copyResourceTo(file, "solaris/x86_64/karaf-wrapper", false); chmod(file, "a+x"); serviceFile = new File(bin, name + "-service"); copyFilteredResourceTo(serviceFile, "unix/karaf-service", props, envs, includes); chmod(serviceFile, "a+x"); wrapperConf = new File(etc, name + "-wrapper.conf"); copyFilteredResourceTo(wrapperConf, "unix/karaf-wrapper.conf", props, envs, includes); mkdir(lib); copyResourceTo(new File(lib, "libwrapper.so"), "solaris/x86_64/libwrapper.so", false); } else { mkdir(bin); File file = new File(bin, name + "-wrapper"); copyResourceTo(file, "solaris/sparc32/karaf-wrapper", false); chmod(file, "a+x"); serviceFile = new File(bin, name + "-service"); copyFilteredResourceTo(serviceFile, "unix/karaf-service", props, envs, includes); chmod(serviceFile, "a+x"); wrapperConf = new File(etc, name + "-wrapper.conf"); copyFilteredResourceTo(wrapperConf, "unix/karaf-wrapper.conf", props, envs, includes); mkdir(lib); copyResourceTo(new File(lib, "libwrapper.so"), "solaris/sparc32/libwrapper.so", false); } } else if (os.startsWith("HP-UX") || os.startsWith("HPUX")) { mkdir(bin); File file = new File(bin, name + "-wrapper"); copyResourceTo(file, "hpux/parisc64/karaf-wrapper", false); chmod(file, "a+x"); serviceFile = new File(bin, name + "-service"); copyFilteredResourceTo(serviceFile, "unix/karaf-service", props, envs, includes); chmod(serviceFile, "a+x"); wrapperConf = new File(etc, name + "-wrapper.conf"); copyFilteredResourceTo(wrapperConf, "unix/karaf-wrapper.conf", props, envs, includes); mkdir(lib); copyResourceTo(new File(lib, "libwrapper.sl"), "hpux/parisc64/libwrapper.sl", false); } else { throw new IllegalStateException("Your operating system '" + os + "' is not currently supported."); } // install the wrapper jar to the lib directory mkdir(lib); copyResourceTo(new File(lib, "karaf-wrapper.jar"), "all/karaf-wrapper.jar", false); mkdir(etc); createJar(new File(lib, "karaf-wrapper-main.jar"), "org/apache/karaf/wrapper/internal/service/Main.class"); File[] wrapperPaths = new File[3]; wrapperPaths[0] = wrapperConf; wrapperPaths[1] = serviceFile; wrapperPaths[2] = systemdFile; return wrapperPaths; } private void mkdir(File file) { if (!file.exists()) { LOGGER.info("Creating missing directory: {}", file.getPath()); System.out.println("Creating missing directory: " + SimpleAnsi.INTENSITY_BOLD + file.getPath() + SimpleAnsi.INTENSITY_NORMAL); file.mkdirs(); } } private void copyResourceTo(File outFile, String resource, boolean text) throws Exception { if (!outFile.exists()) { LOGGER.info("Creating file: {}", outFile.getPath()); System.out.println("Creating file: " + SimpleAnsi.INTENSITY_BOLD + outFile.getPath() + SimpleAnsi.INTENSITY_NORMAL); InputStream is = WrapperServiceImpl.class.getResourceAsStream(resource); if (is == null) { throw new IllegalArgumentException("Resource " + resource + " doesn't exist"); } try { if (text) { // read it line at a time so what we can use the platform line ending when we write it out PrintStream out = new PrintStream(new FileOutputStream(outFile)); try { Scanner scanner = new Scanner(is); while (scanner.hasNextLine()) { String line = scanner.nextLine(); LOGGER.info("writing: {}", line); out.println(line); } } finally { safeClose(out); } } else { // binary resource so just write it out the way it came in FileOutputStream out = new FileOutputStream(outFile); try { int c; while ((c = is.read()) >= 0) { out.write(c); } } finally { safeClose(out); } } } finally { safeClose(is); } } else { LOGGER.warn("File already exists. Move it out of the way if you wish to recreate it: {}", outFile.getPath()); System.out.println( SimpleAnsi.COLOR_RED + "File already exists" + SimpleAnsi.COLOR_DEFAULT + ". Move it out of the way if you wish to recreate it: " + outFile.getPath()); } } private void copyFilteredResourceTo(File outFile, String resource, HashMap<String, String> props, String[] envs, String[] includes) throws Exception { if (!outFile.exists()) { LOGGER.info("Creating file: {}", outFile.getPath()); System.out.println("Creating file: " + SimpleAnsi.INTENSITY_BOLD + outFile.getPath() + SimpleAnsi.INTENSITY_NORMAL); InputStream is = WrapperServiceImpl.class.getResourceAsStream(resource); if (is == null) { throw new IllegalArgumentException("Resource " + resource + " doesn't exist"); } try { // read it line at a time so that we can use the platform line ending when we write it out PrintStream out = new PrintStream(new FileOutputStream(outFile)); try { Scanner scanner = new Scanner(is); while (scanner.hasNextLine()) { String line = scanner.nextLine(); line = filter(line, props); out.println(line); } if (outFile.getName().endsWith(".conf")) { if (envs != null && envs.length > 0) { for (String env : envs) { out.println(env); } } if (includes != null && includes.length > 0) { for (String include : includes) { out.println("#include " + include); } } } } finally { safeClose(out); } } finally { safeClose(is); } } else { LOGGER.warn("File already exists. Move it out of the way if you wish to recreate it: {}", outFile.getPath()); System.out.println( SimpleAnsi.COLOR_RED + "File already exists" + SimpleAnsi.COLOR_DEFAULT + ". Move it out of the way if you wish to recreate it: " + outFile.getPath()); } } private void safeClose(Closeable c) throws IOException { if (c == null) return; try { c.close(); } catch (Throwable ignore) { // nothing to do } } private String filter(String line, HashMap<String, String> props) { for (Map.Entry<String, String> i : props.entrySet()) { int p1 = line.indexOf(i.getKey()); if (p1 >= 0) { String l1 = line.substring(0, p1); String l2 = line.substring(p1 + i.getKey().length()); line = l1 + i.getValue() + l2; } } return line; } private int chmod(File serviceFile, String mode) throws Exception { ProcessBuilder builder = new ProcessBuilder(); builder.command("chmod", mode, serviceFile.getCanonicalPath()); Process p = builder.start(); return p.waitFor(); } private void createJar(File outFile, String resource) throws Exception { if (!outFile.exists()) { LOGGER.info("Creating file: {}", outFile.getPath()); System.out.println("Creating file: " + SimpleAnsi.INTENSITY_BOLD + outFile.getPath() + SimpleAnsi.INTENSITY_NORMAL); InputStream is = getClass().getClassLoader().getResourceAsStream(resource); if (is == null) { throw new IllegalStateException("Resource " + resource + " not found!"); } JarOutputStream jar = null; try { jar = new JarOutputStream(new FileOutputStream(outFile)); int idx = resource.indexOf('/'); while (idx > 0) { jar.putNextEntry(new ZipEntry(resource.substring(0, idx + 1))); jar.closeEntry(); idx = resource.indexOf('/', idx + 1); } jar.putNextEntry(new ZipEntry(resource)); int c; while ((c = is.read()) >= 0) { jar.write(c); } jar.closeEntry(); jar.close(); } finally { safeClose(is); safeClose(jar); } } } @Override public File[] install(String name, String displayName, String description, String startType) throws Exception { return install(name, displayName, description, startType, null, null); } }