001/*
002 * (C) Copyright 2010-2015 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     tdelprat, jcarsique
018 */
019
020package org.nuxeo.ecm.admin;
021
022import java.io.File;
023import java.io.FileOutputStream;
024import java.io.IOException;
025import java.io.OutputStream;
026
027import org.apache.commons.lang.StringUtils;
028import org.apache.commons.lang3.SystemUtils;
029import org.apache.commons.logging.Log;
030import org.apache.commons.logging.LogFactory;
031import org.apache.commons.logging.impl.SimpleLog;
032
033import org.nuxeo.common.Environment;
034import org.nuxeo.launcher.config.ConfigurationGenerator;
035import org.nuxeo.log4j.ThreadedStreamGobbler;
036import org.nuxeo.runtime.api.Framework;
037
038/**
039 * Helper class to call NuxeoCtl restart.
040 *
041 * @author Tiry (tdelprat@nuxeo.com)
042 */
043public class NuxeoCtlManager {
044
045    protected static final String CMD_POSIX = "nuxeoctl";
046
047    protected static final String CMD_WIN = "nuxeoctl.bat";
048
049    protected static final Log log = LogFactory.getLog(NuxeoCtlManager.class);
050
051    private ConfigurationGenerator cg;
052
053    /**
054     * @deprecated Since 7.4. Use {@link SystemUtils#IS_OS_WINDOWS}
055     */
056    @Deprecated
057    public static boolean isWindows() {
058        return SystemUtils.IS_OS_WINDOWS;
059    }
060
061    private static String winEscape(String command) {
062        return command.replaceAll("([ ()<>&])", "^$1");
063    }
064
065    protected static boolean doExec(String path, String logPath) {
066        String[] cmd;
067        if (SystemUtils.IS_OS_WINDOWS) {
068            cmd = new String[] { "cmd", "/C", winEscape(new File(path, CMD_WIN).getPath()), "--gui=false", "restartbg" };
069        } else {
070            cmd = new String[] { "/bin/sh", "-c", "\"" + new File(path, CMD_POSIX).getPath() + "\"" + " restartbg" };
071        }
072
073        Process p1;
074        try {
075            if (log.isDebugEnabled()) {
076                log.debug("Restart command: " + StringUtils.join(cmd, " "));
077            }
078            ProcessBuilder pb = new ProcessBuilder(cmd);
079            p1 = pb.start();
080        } catch (IOException e) {
081            log.error("Unable to restart server", e);
082            return false;
083        }
084
085        if (isWindows()) {
086            File logPathDir = new File(logPath);
087            File out = new File(logPathDir, "restart-" + System.currentTimeMillis() + ".log");
088            File err = new File(logPathDir, "restart-err-" + System.currentTimeMillis() + ".log");
089            OutputStream fout = null;
090            OutputStream ferr = null;
091            try {
092                fout = new FileOutputStream(out);
093                ferr = new FileOutputStream(err);
094            } catch (IOException e) {
095                throw new RuntimeException(e);
096            }
097            new ThreadedStreamGobbler(p1.getInputStream(), fout).start();
098            new ThreadedStreamGobbler(p1.getErrorStream(), ferr).start();
099        } else {
100            new ThreadedStreamGobbler(p1.getInputStream(), SimpleLog.LOG_LEVEL_OFF).start();
101            new ThreadedStreamGobbler(p1.getErrorStream(), SimpleLog.LOG_LEVEL_ERROR).start();
102        }
103        return true;
104    }
105
106    private static boolean restartInProgress = false;
107
108    public static synchronized boolean restart() {
109        if (restartInProgress) {
110            return false;
111        }
112        restartInProgress = true;
113        String nuxeoHome = Framework.getProperty(Environment.NUXEO_HOME);
114        final String binPath = new File(nuxeoHome, "bin").getPath();
115        final String logDir = Framework.getProperty(Environment.NUXEO_LOG_DIR, nuxeoHome);
116        new Thread("restart thread") {
117            @Override
118            public void run() {
119                try {
120                    log.info("Restarting Nuxeo server");
121                    Thread.sleep(3000);
122                    doExec(binPath, logDir);
123                } catch (InterruptedException e) {
124                    log.error("Restart failed", e);
125                }
126            }
127        }.start();
128        return true;
129    }
130
131    public String restartServer() {
132        restart();
133        return "Nuxeo server is restarting";
134    }
135
136    /**
137     * @since 5.6
138     * @return Configured server URL (may differ from current URL)
139     */
140    public String getServerURL() {
141        if (cg == null) {
142            cg = new ConfigurationGenerator();
143            cg.init();
144        }
145        return cg.getUserConfig().getProperty(ConfigurationGenerator.PARAM_NUXEO_URL);
146    }
147
148}