com.adito.server.ServerLock.java Source code

Java tutorial

Introduction

Here is the source code for com.adito.server.ServerLock.java

Source

/*
*  Adito
*
*  Copyright (C) 2003-2006 3SP LTD. All Rights Reserved
*
*  This program is free software; you can redistribute it and/or
*  modify it under the terms of the GNU General Public License
*  as published by the Free Software Foundation; either version 2 of
*  the License, or (at your option) any later version.
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public
*  License along with this program; if not, write to the Free Software
*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

package com.adito.server;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.StringTokenizer;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.adito.boot.ContextHolder;
import com.adito.boot.Util;

/**
 * Used to determine if Adito (or some other server) is already running
 * under a different runtime. The check also determines if the already running
 * the installation wizard.
 * <p>
 * This mechanism also provides a way for the server to be shutdown use a
 * scrip. Once created, the lock file is watched and if it changes to contain
 * the text "shutdown" then the server will be shutdown.
 */
public class ServerLock {

    /**
     * Name of the lock file
     */
    public final static String LOCK_NAME = "server.run";

    final static Log log = LogFactory.getLog(ServerLock.class);

    private File lockFile;
    private boolean locked;
    private boolean setup;
    private int port;
    private String bindAddress;
    private boolean started;
    private long lastLockChange;

    /**
     * Constructor. The lock will be searched for, and if a service is known to
     * be already running an exception is thrown.
     * 
     * @param bindAddress address of interface server is bound to
     * @throws IOException if the service is already running
     * 
     */
    public ServerLock(String bindAddress) throws IOException {

        this.bindAddress = bindAddress;
        lockFile = new File(ContextHolder.getContext().getTempDirectory(), LOCK_NAME);

        /*
         * Check that Adito is not already running using file locks. If
         * the file exists but is not locked, then this may be have been an
         * unclean shutdown
         */
        if (lockFile.exists()) {
            FileInputStream lockIn = null;
            try {
                lockIn = new FileInputStream(lockFile);
                BufferedReader br = new BufferedReader(new InputStreamReader(lockIn));
                String r = br.readLine();
                if (r != null && !r.equals("")) {
                    try {
                        if (!r.equals("shutdown") || r.equals("restart")) {
                            StringTokenizer t = new StringTokenizer(r, ":");
                            setup = "true".equals(t.nextToken());
                            port = Integer.parseInt(t.nextToken());
                            checkStatus();
                        }
                    } catch (Exception e) {
                        System.err.println("Could not parse lock file.");
                        e.printStackTrace();
                    }
                }
            } finally {
                Util.closeStream(lockIn);
            }
        }
    }

    /**
     * Get if a service is already running.
     * 
     * @return server is locked
     */
    public boolean isLocked() {
        return locked;
    }

    /**
     * Should be called when the service starts. This checks if a service is
     * already running, and if not creates the lock so future instances know.
     * 
     * @param port port the service is running on
     * @throws IOException
     */
    public void start(int port) throws IOException {
        this.port = port;
        this.setup = ContextHolder.getContext().isSetupMode();

        /*
         * Check whether there is already a listener on the port, this means we
         * can throw a more meaningful exception than jetty does if a server
         * other than Adito is already running on this port
         */
        checkStatus();
        if (locked) {
            if (port == 443 || port == 8443) {
                throw new IOException("Some other server is already running on port " + port + "."
                        + "Most web servers will run on this port by default, so check if you have such "
                        + "a service is installed (IIS, Apache or Tomcat for example). Either shutdown "
                        + "and disable the conflicting server, or if you wish to run both services "
                        + "concurrently, change the port number on which one listens.");
            } else {
                throw new IOException("Some other server is already running on port " + port + "."
                        + "Check which other services you have enabled that may be causing "
                        + "this conflict. Then, either disable the service, change the port on "
                        + "which it is listening or change the port on which this server listens.");

            }
        }

        //
        PrintWriter pw = new PrintWriter(new FileOutputStream(lockFile));
        pw.println(ContextHolder.getContext().isSetupMode() + ":" + port);
        pw.flush();
        pw.close();
        started = true;

        lastLockChange = lockFile.lastModified();

        /* Start watching the lock file, if it disappears then shut down the
         * server
         */
        Thread t = new Thread("ServerLockMonitor") {
            public void run() {
                while (true) {
                    try {
                        Thread.sleep(5000);
                        if (lastLockChange != lockFile.lastModified()) {
                            lastLockChange = lockFile.lastModified();
                            if (log.isDebugEnabled())
                                log.debug("Lock file changed, examining");
                            InputStream in = null;
                            try {
                                in = new FileInputStream(lockFile);
                                ;
                                BufferedReader br = new BufferedReader(new InputStreamReader(in));
                                String s = br.readLine();
                                Util.closeStream(in); // close so we can delete
                                if ("shutdown".equals(s)) {
                                    ContextHolder.getContext().shutdown(false);
                                    break;
                                } else if ("restart".equals(s)) {
                                    ContextHolder.getContext().shutdown(true);
                                    break;
                                }
                            } catch (IOException ioe) {
                                Util.closeStream(in);
                                throw ioe;
                            }
                        }
                    } catch (Exception e) {
                    }
                }
            }
        };
        t.setDaemon(true);
        t.setPriority(Thread.MIN_PRIORITY);
        t.start();

    }

    /**
     * Get if this instance started and is running
     * 
     * @return started
     * 
     */
    public boolean isStarted() {
        return started;
    }

    /**
     * Remove the lock and clean up. Should be called when the server shuts
     * down.
     */
    public void stop() {
        if (log.isInfoEnabled())
            log.info("Removing lock");
        lockFile.delete();
        started = false;
    }

    /**
     * Get if the currently running service is running the installation wizard.
     * 
     * @return running installation wizard
     */
    public boolean isSetup() {
        return setup;
    }

    /**
     * Get the port the currently running service is running on
     * 
     * @return port
     */
    public int getPort() {
        return port;
    }

    private void checkStatus() {
        Socket socket = null;
        try {
            int timeout = 5000; // 5 seconds
            if (log.isInfoEnabled())
                log.info("Connecting to " + bindAddress + ":" + port + " to see if a server is already running.");
            SocketAddress socketAddress = new InetSocketAddress(bindAddress, port);
            socket = new Socket();
            socket.connect(socketAddress, timeout);
            locked = true;
        } catch (Exception e) {
            locked = false;
        } finally {
            if (socket != null) {
                try {
                    socket.close();
                } catch (Exception e) {

                }
            }
        }
    }

}