| /* |
| * 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.shell.wrapper; |
| |
| import java.io.File; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.io.PrintStream; |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.Scanner; |
| import java.util.jar.JarOutputStream; |
| import java.util.zip.ZipEntry; |
| |
| import org.apache.karaf.shell.console.OsgiCommandSupport; |
| import org.apache.felix.gogo.commands.Option; |
| import org.apache.felix.gogo.commands.Command; |
| import org.fusesource.jansi.Ansi; |
| |
| /** |
| * Installs this Karaf instance as a service in your operating systems. |
| * |
| * @version $Rev: 603634 $ $Date: 2007-12-12 16:07:16 +0100 (Wed, 12 Dec 2007) $ |
| */ |
| @Command(scope = "wrapper", name = "install", description = "Install the container as a system service in the OS.") |
| public class InstallCommand extends OsgiCommandSupport { |
| @Option(name = "-n", aliases = {"--name"}, description = "The service name that will be used when installing the service. (Default: karaf)", required = false, multiValued = false) |
| private String name = "karaf"; |
| |
| @Option(name = "-d", aliases = {"--display"}, description = "The display name of the service.", required = false, multiValued = false) |
| private String displayName; |
| |
| @Option(name = "-D", aliases = {"--description"}, description = "The description of the service.", required = false, multiValued = false) |
| private String description = ""; |
| |
| @Option(name = "-s", aliases = {"--start-type"}, description = "Mode in which the service is installed. AUTO_START or DEMAND_START (Default: AUTO_START)", required = false, multiValued = false) |
| private String startType = "AUTO_START"; |
| |
| protected Object doExecute() throws Exception { |
| |
| try { |
| String name = getName(); |
| File base = new File(System.getProperty("karaf.base")); |
| File bin = new File(base, "bin"); |
| File etc = new File(base, "etc"); |
| File lib = new File(base, "lib"); |
| |
| HashMap<String, String> props = new HashMap<String, String>(); |
| props.put("${karaf.home}", System.getProperty("karaf.home")); |
| props.put("${karaf.base}", base.getPath()); |
| props.put("${karaf.data}", System.getProperty("karaf.data")); |
| props.put("${name}", name); |
| props.put("${displayName}", getDisplayName()); |
| props.put("${description}", getDescription()); |
| props.put("${startType}", getStartType()); |
| |
| String os = System.getProperty("os.name", "Unknown"); |
| File serviceFile = null; |
| File wrapperConf = 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); |
| |
| copyFilteredResourceTo(serviceFile, "windows64/karaf-service.bat", props); |
| |
| 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); |
| |
| copyFilteredResourceTo(serviceFile, "windows/karaf-service.bat", props); |
| |
| 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); |
| chmod(serviceFile, "a+x"); |
| |
| wrapperConf = new File(etc, name + "-wrapper.conf"); |
| copyFilteredResourceTo(wrapperConf, "unix/karaf-wrapper.conf", props); |
| |
| mkdir(lib); |
| copyResourceTo(new File(lib, "libwrapper.jnilib"), "macosx/libwrapper.jnilib", false); |
| |
| // TODO: figure out how to hook in the service that it starts up |
| // when the machine boots up. |
| } 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); |
| chmod(serviceFile, "a+x"); |
| |
| wrapperConf = new File(etc, name + "-wrapper.conf"); |
| copyFilteredResourceTo(wrapperConf, "unix/karaf-wrapper.conf", props); |
| |
| 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); |
| chmod(serviceFile, "a+x"); |
| |
| wrapperConf = new File(etc, name + "-wrapper.conf"); |
| copyFilteredResourceTo(wrapperConf, "unix/karaf-wrapper.conf", props); |
| |
| mkdir(lib); |
| copyResourceTo(new File(lib, "libwrapper.so"), "linux/libwrapper.so", false); |
| |
| // TODO: figure out how to hook in the service that it starts up |
| // when the machine boots up. |
| } |
| } 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"); |
| copyResourceTo(file, "unix/karaf-service", false); |
| chmod(file, "a+x"); |
| |
| wrapperConf = new File(etc, name + "-wrapper.conf"); |
| copyFilteredResourceTo(wrapperConf, "unix/karaf-wrapper.conf", props); |
| |
| 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/ppc64/karaf-wrapper", false); |
| chmod(file, "a+x"); |
| |
| serviceFile = new File(bin, name + "-service"); |
| copyResourceTo(file, "unix/karaf-service", false); |
| chmod(file, "a+x"); |
| |
| wrapperConf = new File(etc, name + "-wrapper.conf"); |
| copyFilteredResourceTo(wrapperConf, "unix/karaf-wrapper.conf", props); |
| |
| mkdir(lib); |
| copyResourceTo(new File(lib, "libwrapper.a"), "aix/ppc64/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"); |
| copyResourceTo(file, "unix/karaf-service", false); |
| chmod(file, "a+x"); |
| |
| wrapperConf = new File(etc, name + "-wrapper.conf"); |
| copyFilteredResourceTo(wrapperConf, "unix/karaf-wrapper.conf", props); |
| |
| 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"); |
| copyResourceTo(file, "unix/karaf-service", false); |
| chmod(file, "a+x"); |
| |
| wrapperConf = new File(etc, name + "-wrapper.conf"); |
| copyFilteredResourceTo(wrapperConf, "unix/karaf-wrapper.conf", props); |
| |
| mkdir(lib); |
| copyResourceTo(new File(lib, "libwrapper.so"), "solaris/x86/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"); |
| copyResourceTo(file, "unix/karaf-service", false); |
| chmod(file, "a+x"); |
| |
| wrapperConf = new File(etc, name + "-wrapper.conf"); |
| copyFilteredResourceTo(wrapperConf, "unix/karaf-wrapper.conf", props); |
| |
| 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"); |
| copyResourceTo(file, "unix/karaf-service", false); |
| chmod(file, "a+x"); |
| |
| wrapperConf = new File(etc, name + "-wrapper.conf"); |
| copyFilteredResourceTo(wrapperConf, "unix/karaf-wrapper.conf", props); |
| |
| mkdir(lib); |
| copyResourceTo(new File(lib, "libwrapper.sl"), "hpux/parisc64/libwrapper.sl", false); |
| } else { |
| System.out.println("Your operating system '" + os + "' is not currently supported."); |
| return 1; |
| } |
| |
| // 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/shell/wrapper/Main.class"); |
| |
| System.out.println(""); |
| System.out.println("Setup complete. You may wish to tweak the JVM properties in the wrapper configuration file:"); |
| System.out.println("\t" + wrapperConf.getPath()); |
| System.out.println("before installing and starting the service."); |
| System.out.println(""); |
| if (os.startsWith("Win")) { |
| System.out.println(""); |
| System.out.println("To install the service, run: "); |
| System.out.println(" C:> " + serviceFile.getPath() + " install"); |
| System.out.println(""); |
| System.out.println("Once installed, to start the service run: "); |
| System.out.println(" C:> net start \"" + name + "\""); |
| System.out.println(""); |
| System.out.println("Once running, to stop the service run: "); |
| System.out.println(" C:> net stop \"" + name + "\""); |
| System.out.println(""); |
| System.out.println("Once stopped, to remove the installed the service run: "); |
| System.out.println(" C:> " + serviceFile.getPath() + " remove"); |
| System.out.println(""); |
| } else if (os.startsWith("Mac OS X")) { |
| System.out.println(""); |
| System.out.println("At this time it is not known how to get this service to start when the machine is rebooted."); |
| System.out.println("If you know how to install the following service script so that it gets started"); |
| System.out.println("when OS X starts, please email dev@felix.apache.org and let us know how so"); |
| System.out.println("we can update this message."); |
| System.out.println(" "); |
| System.out.println(" To start the service:"); |
| System.out.println(" $ " + serviceFile.getPath() + " start"); |
| System.out.println(""); |
| System.out.println(" To stop the service:"); |
| System.out.println(" $ " + serviceFile.getPath() + " stop"); |
| System.out.println(""); |
| } else if (os.startsWith("Linux")) { |
| System.out.println("The way the service is installed depends upon your flavor of Linux."); |
| |
| // TODO: figure out if we can detect the Linux flavor |
| |
| System.out.println(""); |
| System.out.println(Ansi.ansi().a(Ansi.Attribute.INTENSITY_BOLD).a("On Redhat/Fedora/CentOS Systems:").a(Ansi.Attribute.RESET).toString()); |
| System.out.println(" To install the service:"); |
| System.out.println(" $ ln -s " + serviceFile.getPath() + " /etc/init.d/"); |
| System.out.println(" $ chkconfig " + serviceFile.getName() + " --add"); |
| System.out.println(""); |
| System.out.println(" To start the service when the machine is rebooted:"); |
| System.out.println(" $ chkconfig " + serviceFile.getName() + " on"); |
| System.out.println(""); |
| System.out.println(" To disable starting the service when the machine is rebooted:"); |
| System.out.println(" $ chkconfig " + serviceFile.getName() + " off"); |
| System.out.println(""); |
| System.out.println(" To start the service:"); |
| System.out.println(" $ service " + serviceFile.getName() + " start"); |
| System.out.println(""); |
| System.out.println(" To stop the service:"); |
| System.out.println(" $ service " + serviceFile.getName() + " stop"); |
| System.out.println(""); |
| System.out.println(" To uninstall the service :"); |
| System.out.println(" $ chkconfig " + serviceFile.getName() + " --del"); |
| System.out.println(" $ rm /etc/init.d/" + serviceFile.getName()); |
| |
| System.out.println(""); |
| System.out.println(Ansi.ansi().a(Ansi.Attribute.INTENSITY_BOLD).a("On Ubuntu/Debian Systems:").a(Ansi.Attribute.RESET).toString()); |
| System.out.println(" To install the service:"); |
| System.out.println(" $ ln -s " + serviceFile.getPath() + " /etc/init.d/"); |
| System.out.println(""); |
| System.out.println(" To start the service when the machine is rebooted:"); |
| System.out.println(" $ update-rc.d " + serviceFile.getName() + " defaults"); |
| System.out.println(""); |
| System.out.println(" To disable starting the service when the machine is rebooted:"); |
| System.out.println(" $ update-rc.d -f " + serviceFile.getName() + " remove"); |
| System.out.println(""); |
| System.out.println(" To start the service:"); |
| System.out.println(" $ /etc/init.d/" + serviceFile.getName() + " start"); |
| System.out.println(""); |
| System.out.println(" To stop the service:"); |
| System.out.println(" $ /etc/init.d/" + serviceFile.getName() + " stop"); |
| System.out.println(""); |
| System.out.println(" To uninstall the service :"); |
| System.out.println(" $ rm /etc/init.d/" + serviceFile.getName()); |
| |
| } |
| |
| |
| } catch (Exception e) { |
| e.printStackTrace(); |
| throw e; |
| } |
| |
| return null; |
| } |
| |
| private int chmod(File serviceFile, String mode) throws Exception { |
| ProcessBuilder builder = new ProcessBuilder(); |
| builder.command("chmod", mode, serviceFile.getCanonicalPath()); |
| Process p = builder.start(); |
| |
| PumpStreamHandler handler = new PumpStreamHandler(System.in, System.out, System.err); |
| handler.attach(p); |
| handler.start(); |
| int status = p.waitFor(); |
| handler.stop(); |
| return status; |
| } |
| |
| private void createJar(File outFile, String resource) throws Exception { |
| if (!outFile.exists()) { |
| System.out.println(Ansi.ansi().a("Creating file: ") |
| .a(Ansi.Attribute.INTENSITY_BOLD).a(outFile.getPath()).a(Ansi.Attribute.RESET).toString()); |
| InputStream is = getClass().getClassLoader().getResourceAsStream(resource); |
| if (is == null) { |
| throw new IllegalStateException("Resource " + resource + " not found!"); |
| } |
| try { |
| JarOutputStream jar = new JarOutputStream(new FileOutputStream(outFile)); |
| int idx = resource.indexOf('/'); |
| while (idx > 0) { |
| jar.putNextEntry(new ZipEntry(resource.substring(0, idx))); |
| 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); |
| } |
| } |
| } |
| |
| private void copyResourceTo(File outFile, String resource, boolean text) throws Exception { |
| if (!outFile.exists()) { |
| System.out.println(Ansi.ansi().a("Creating file: ") |
| .a(Ansi.Attribute.INTENSITY_BOLD).a(outFile.getPath()).a(Ansi.Attribute.RESET).toString()); |
| InputStream is = InstallCommand.class.getResourceAsStream(resource); |
| try { |
| if (text) { |
| // 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(); |
| System.out.println("writing: " + line); |
| out.println(line); |
| } |
| } finally { |
| safeClose(out); |
| } |
| } else { |
| // Binary so just write it out the way it came in. |
| FileOutputStream out = new FileOutputStream(outFile); |
| try { |
| int c = 0; |
| while ((c = is.read()) >= 0) { |
| out.write(c); |
| } |
| } finally { |
| safeClose(out); |
| } |
| } |
| } finally { |
| safeClose(is); |
| } |
| } else { |
| System.out.println(Ansi.ansi() |
| .fg(Ansi.Color.RED).a("File already exists").a(Ansi.Attribute.RESET) |
| .a(". Move it out of the way if you wish to recreate it: ").a(outFile.getPath()).toString()); |
| } |
| } |
| |
| private void copyFilteredResourceTo(File outFile, String resource, HashMap<String, String> props) throws Exception { |
| if (!outFile.exists()) { |
| System.out.println(Ansi.ansi().a("Creating file: ") |
| .a(Ansi.Attribute.INTENSITY_BOLD).a(outFile.getPath()).a(Ansi.Attribute.RESET).toString()); |
| InputStream is = InstallCommand.class.getResourceAsStream(resource); |
| 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); |
| } |
| } finally { |
| safeClose(out); |
| } |
| } finally { |
| safeClose(is); |
| } |
| } else { |
| System.out.println(Ansi.ansi() |
| .fg(Ansi.Color.RED).a("File already exists").a(Ansi.Attribute.RESET) |
| .a(". Move it out of the way if you wish to recreate it: ").a(outFile.getPath()).toString()); |
| } |
| } |
| |
| private void safeClose(InputStream is) throws IOException { |
| if (is == null) |
| return; |
| try { |
| is.close(); |
| } catch (Throwable ignore) { |
| } |
| } |
| |
| private void safeClose(OutputStream is) throws IOException { |
| if (is == null) |
| return; |
| try { |
| is.close(); |
| } catch (Throwable ignore) { |
| } |
| } |
| |
| 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 void mkdir(File file) { |
| if (!file.exists()) { |
| System.out.println(Ansi.ansi().a("Creating missing directory: ") |
| .a(Ansi.Attribute.INTENSITY_BOLD).a(file.getPath()).a(Ansi.Attribute.RESET).toString()); |
| file.mkdirs(); |
| } |
| } |
| |
| public String getName() { |
| if (name == null) { |
| File base = new File(System.getProperty("karaf.base")); |
| name = base.getName(); |
| } |
| return name; |
| } |
| |
| public void setName(String name) { |
| this.name = name; |
| } |
| |
| public String getDisplayName() { |
| if (displayName == null) { |
| displayName = getName(); |
| } |
| return displayName; |
| } |
| |
| public void setDisplayName(String displayName) { |
| this.displayName = displayName; |
| } |
| |
| public String getDescription() { |
| return description; |
| } |
| |
| public void setDescription(String description) { |
| this.description = description; |
| } |
| |
| public String getStartType() { |
| return startType; |
| } |
| |
| public void setStartType(String startType) { |
| this.startType = startType; |
| } |
| } |