Package org.apache.karaf.instance.core.internal

Source Code of org.apache.karaf.instance.core.internal.InstanceImpl

/*
* 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.instance.core.internal;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.net.URL;
import java.net.UnknownHostException;

import org.apache.felix.utils.properties.Properties;
import org.apache.karaf.instance.core.Instance;
import org.apache.karaf.jpm.Process;
import org.apache.karaf.jpm.ProcessBuilderFactory;
import org.apache.karaf.jpm.impl.ProcessBuilderFactoryImpl;
import org.apache.karaf.jpm.impl.ScriptUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class InstanceImpl implements Instance {

    private static final Logger LOG = LoggerFactory.getLogger(InstanceImpl.class);

    private static final String CONFIG_PROPERTIES_FILE_NAME = "config.properties";
    private static final String KARAF_SHUTDOWN_PORT = "karaf.shutdown.port";
    private static final String KARAF_SHUTDOWN_HOST = "karaf.shutdown.host";
    private static final String KARAF_SHUTDOWN_PORT_FILE = "karaf.shutdown.port.file";
    private static final String KARAF_SHUTDOWN_COMMAND = "karaf.shutdown.command";
    private static final String DEFAULT_SHUTDOWN_COMMAND = "SHUTDOWN";

    private InstanceServiceImpl service;
    private String name;
    private String location;
    private String javaOpts;
    private Process process;
    private boolean root;

    private final ProcessBuilderFactory processBuilderFactory;

    public InstanceImpl(InstanceServiceImpl service, String name, String location, String javaOpts) {
        this(service, name, location, javaOpts, false);
       
    }
   
    public InstanceImpl(InstanceServiceImpl service, String name, String location, String javaOpts, boolean root) {
        this.service = service;
        this.name = name;
        this.location = location;
        this.javaOpts = javaOpts;
        this.root = root;
        this.processBuilderFactory = new ProcessBuilderFactoryImpl();
    }

    public void attach(int pid) throws IOException {
        checkProcess();
        if (this.process != null) {
            throw new IllegalStateException("Instance already started");
        }
        this.process = processBuilderFactory.newBuilder().attach(pid);
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }
   
    public boolean isRoot() {
        return root;
    }

    public String getLocation() {
        return location;
    }

    public void setLocation(String location) {
        this.location = location;
    }

    public boolean exists() {
        return new File(location).isDirectory();
    }

    public int getPid() {
        checkProcess();
        return this.process != null ? this.process.getPid() : 0;
    }

    public int getSshPort() {
        try {
            String loc = this.getConfiguration(new File(location, "etc/org.apache.karaf.shell.cfg"), "sshPort");
            return Integer.parseInt(loc);
        } catch (Exception e) {
            return 0;
        }
    }

    public void changeSshPort(int port) throws Exception {
        checkProcess();
        if (this.process != null) {
            throw new IllegalStateException("Instance not stopped");
        }
        this.changeConfiguration(new File(location, "etc/org.apache.karaf.shell.cfg"),
                "sshPort", Integer.toString(port));
    }

    public int getRmiRegistryPort() {
        try {
            String loc = this.getConfiguration(new File(location, "etc/org.apache.karaf.management.cfg"), "rmiRegistryPort");
            return Integer.parseInt(loc);
        } catch (Exception e) {
            return 0;
        }
    }

    public void changeRmiRegistryPort(int port) throws Exception {
        checkProcess();
        if (this.process != null) {
            throw new IllegalStateException("Instance not stopped");
        }
        this.changeConfiguration(new File(location, "etc/org.apache.karaf.management.cfg"),
                "rmiRegistryPort", Integer.toString(port));
    }

    public int getRmiServerPort() {
        try {
            String loc = this.getConfiguration(new File(location, "etc/org.apache.karaf.management.cfg"), "rmiServerPort");
            return Integer.parseInt(loc);
        } catch (Exception e) {
            return 0;
        }
    }

    public void changeRmiServerPort(int port) throws Exception {
        checkProcess();
        if (this.process != null) {
            throw new IllegalStateException("Instance not stopped");
        }
        this.changeConfiguration(new File(location, "etc/org.apache.karaf.management.cfg"),
                "rmiServerPort", Integer.toString(port));
    }

    /**
     * Change a configuration property in a given configuration file.
     *
     * @param configurationFile the configuration file where to update the configuration property.
     * @param propertyName the property name.
     * @param propertyValue the property value.
     * @throws Exception if a failure occurs.
     */
    private void changeConfiguration(File configurationFile, String propertyName, String propertyValue) throws Exception {
        Properties props = new Properties();
        InputStream is = new FileInputStream(configurationFile);
        try {
            props.load(is);
        } finally {
            is.close();
        }
        props.put(propertyName, propertyValue);
        OutputStream os = new FileOutputStream(configurationFile);
        try {
            props.save(os);
        } finally {
            os.close();
        }
    }

    /**
     * Read a given configuration file to get the value of a given property.
     *
     * @param configurationFile the configuration file where to lookup property.
     * @param propertyName the property name to look for.
     * @return the property value.
     * @throws Exception in case of read failure.
     */
    private String getConfiguration(File configurationFile, String propertyName) throws Exception {
        Properties props = loadPropertiesFile(configurationFile.toURI().toURL());
        return props.getProperty(propertyName);
    }

    public String getJavaOpts() {
        return javaOpts;
    }

    public void changeJavaOpts(String javaOpts) throws Exception {
        this.javaOpts = javaOpts;
        this.service.saveState();
    }

    public synchronized void start(String javaOpts) throws Exception {
        checkProcess();
        if (this.process != null) {
            throw new IllegalStateException("Instance already started");
        }
        if (javaOpts == null || javaOpts.length() == 0) {
            javaOpts = this.javaOpts;
        }
        if (javaOpts == null || javaOpts.length() == 0) {
            javaOpts = "-server -Xmx512M -Dcom.sun.management.jmxremote";
        }
        String karafOpts = System.getProperty("karaf.opts", "")
       
        File libDir = new File(System.getProperty("karaf.home"), "lib");
        String classpath = createClasspathFromAllJars(libDir);
        String endorsedDirs = getSubDirs(libDir, "endorsed");
        String extDirs = getSubDirs(libDir, "ext");

        String command = "\"" + ScriptUtils.getJavaCommandPath() + "\" " + javaOpts + " " + karafOpts
                + " -Djava.util.logging.config.file=\"" + new File(location, "etc/java.util.logging.properties").getCanonicalPath() + "\""
                + " -Djava.endorsed.dirs=\"" + endorsedDirs + "\""
                + " -Djava.ext.dirs=\"" + extDirs + "\""
                + " -Dkaraf.home=\"" + System.getProperty("karaf.home") + "\""
                + " -Dkaraf.base=\"" + new File(location).getCanonicalPath() + "\""
                + " -Dkaraf.startLocalConsole=false"
                + " -Dkaraf.startRemoteShell=true"
                + " -classpath " + classpath.toString()
                + " org.apache.karaf.main.Main";
        LOG.debug("Starting instance " + name + " with command: " + command);
        this.process = processBuilderFactory.newBuilder()
                        .directory(new File(location))
                        .command(command)
                        .start();
        this.service.saveState();
    }

    private String getSubDirs(File libDir, String subDir) throws IOException {
        File jreLibDir = new File(new File(System.getProperty("java.home"), "jre"), "lib");
        File javaLibDir = new File(System.getProperty("java.home"), "lib");
        String sep = System.getProperty("path.separator");
        return new File(jreLibDir, subDir) + sep + new File(javaLibDir, subDir) + sep + new File(libDir, subDir).getCanonicalPath();
    }

    private String createClasspathFromAllJars(File libDir) throws IOException {
        File[] jars = libDir.listFiles(new FilenameFilter() {
            public boolean accept(File dir, String name) {
                return name.endsWith(".jar");
            }
        });
        StringBuilder classpath = new StringBuilder();
        for (File jar : jars) {
            if (classpath.length() > 0) {
                classpath.append(System.getProperty("path.separator"));
            }
            classpath.append(jar.getCanonicalPath());
        }
        return classpath.toString();
    }

    public synchronized void stop() throws Exception {
        checkProcess();
        if (this.process == null) {
            throw new IllegalStateException("Instance not started");
        }
        // Try a clean shutdown
        cleanShutdown();
        if (this.process != null) {
            this.process.destroy();
        }
    }

    public synchronized void destroy() throws Exception {
        checkProcess();
        if (this.process != null) {
            throw new IllegalStateException("Instance not stopped");
        }
        deleteFile(new File(location));
        this.service.forget(name);
        this.service.saveState();
    }

    public synchronized String getState() {
        int port = getSshPort();
        if (!exists() || port <= 0) {
            return ERROR;
        }
        checkProcess();
        if (this.process == null) {
            return STOPPED;
        } else {
            try {
                Socket s = new Socket("localhost", port);
                s.close();
                return STARTED;
            } catch (Exception e) {
                // ignore
            }
            return STARTING;
        }
    }

    protected void checkProcess() {
        if (this.process != null) {
            try {
                if (!this.process.isRunning()) {
                    this.process = null;
                }
            } catch (IOException e) {
            }
        }
    }

    protected void cleanShutdown() {
        try {
            File file = new File(new File(location, "etc"), CONFIG_PROPERTIES_FILE_NAME);
            URL configPropURL = file.toURI().toURL();
            Properties props = loadPropertiesFile(configPropURL);

            String host = props.getProperty(KARAF_SHUTDOWN_HOST, "localhost");
           
            String shutdown = props.getProperty(KARAF_SHUTDOWN_COMMAND, DEFAULT_SHUTDOWN_COMMAND);
           
            int port = getShutDownPort(props);

            // We found the port, try to send the command
            if (port > 0) {
                tryShutDownAndWait(host, shutdown, port, service.getStopTimeout());
            }
        } catch (Exception e) {
            LOG.debug("Unable to cleanly shutdown instance", e);
        }
    }

  private void tryShutDownAndWait(String host, String shutdownCommand, int port, long stopTimeout)
      throws UnknownHostException, IOException, InterruptedException {
    Socket s = new Socket(host, port);
    s.getOutputStream().write(shutdownCommand.getBytes());
    s.close();
    long t = System.currentTimeMillis() + stopTimeout;
    do {
        Thread.sleep(100);
        checkProcess();
    } while (System.currentTimeMillis() < t && process != null);
  }

  private int getShutDownPort(Properties props) throws FileNotFoundException,
      IOException {
       
        int port = Integer.parseInt(props.getProperty(KARAF_SHUTDOWN_PORT, "0"));

    // Try to get port from port file
    String portFile = props.getProperty(KARAF_SHUTDOWN_PORT_FILE);
    if (port == 0 && portFile != null) {
        BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(portFile)));
        String portStr = r.readLine();
        port = Integer.parseInt(portStr);
        r.close();
    }
    return port;
  }

    protected static boolean deleteFile(File fileToDelete) {
        if (fileToDelete == null || !fileToDelete.exists()) {
            return true;
        }
        boolean result = true;
        if (fileToDelete.isDirectory()) {
            File[] files = fileToDelete.listFiles();
            if (files == null) {
                result = false;
            } else {
                for (int i = 0; i < files.length; i++) {
                    File file = files[i];
                    if (file.getName().equals(".") || file.getName().equals("..")) {
                        continue;
                    }
                    if (file.isDirectory()) {
                        result &= deleteFile(file);
                    } else {
                        result &= file.delete();
                    }
                }
            }
        }
        result &= fileToDelete.delete();
        return result;
    }

    protected Properties loadPropertiesFile(URL configPropURL) throws Exception {
        // Read the properties file.
        Properties configProps = new Properties();
        InputStream is = null;
        try {
            configProps.put("karaf.base", new File(location).getCanonicalPath());
            configProps.put("karaf.home", System.getProperty("karaf.home"));
            configProps.put("karaf.data", new File(new File(location), "data").getCanonicalPath());
            is = configPropURL.openConnection().getInputStream();
            configProps.load(is);
            return configProps;
        } catch (Exception ex) {
          throw new RuntimeException("Error loading config properties from " + configPropURL, ex);
        } finally {
          try {
                if (is != null) is.close();
            }
            catch (IOException ex2) {
                LOG.warn(ex2.getMessage(), ex2);
            }
        }
    }

    public boolean isAttached() {
        checkProcess();
        return (process != null);
    }


}
TOP

Related Classes of org.apache.karaf.instance.core.internal.InstanceImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.