org.apache.jcs.auxiliary.remote.server.RemoteCacheServerFactory.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.jcs.auxiliary.remote.server.RemoteCacheServerFactory.java

Source

package org.apache.jcs.auxiliary.remote.server;

/*
 * 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.
 */

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.Socket;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.registry.Registry;
import java.rmi.server.RMISocketFactory;
import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.jcs.auxiliary.remote.RemoteUtils;
import org.apache.jcs.auxiliary.remote.behavior.IRemoteCacheConstants;
import org.apache.jcs.auxiliary.remote.behavior.IRemoteCacheServiceAdmin;

/**
 * Provides remote cache services. This creates remote cache servers and can proxy command line
 * requests to a running server.
 */
public class RemoteCacheServerFactory implements IRemoteCacheConstants {
    private final static Log log = LogFactory.getLog(RemoteCacheServerFactory.class);

    /** The single instance of the RemoteCacheServer object. */
    private static RemoteCacheServer remoteCacheServer;

    private static String serviceName;

    private static int DEFAULT_RMI_SOCKET_FACTORY_TIMEOUT_MS = 10000;

    /** Constructor for the RemoteCacheServerFactory object. */
    private RemoteCacheServerFactory() {
        super();
    }

    /**
     * This will allow you to get stats from the server, etc. Perhaps we should provide methods on
     * the factory to do this instead.
     * A remote cache is either a local cache or a cluster cache
     * @return Returns the remoteCacheServer.
     */
    public static RemoteCacheServer getRemoteCacheServer() {
        return remoteCacheServer;
    }

    // ///////////////////// Statup/shutdown methods. //////////////////
    /**
     * Starts up the remote cache server on this JVM, and binds it to the registry on the given host
     * and port.
     * A remote cache is either a local cache or a cluster cache
     * @param host
     * @param port
     * @param propFile
     * @throws IOException
     */
    public static void startup(String host, int port, String propFile) throws IOException {
        if (remoteCacheServer != null) {
            throw new IllegalArgumentException("Server already started.");
        }

        synchronized (RemoteCacheServer.class) {
            if (remoteCacheServer != null) {
                return;
            }

            if (log.isInfoEnabled()) {
                log.info("ConfigFileName = [" + propFile + "]");
            }

            try {
                // TODO make configurable.
                // use this socket factory to add a timeout.
                RMISocketFactory.setSocketFactory(new RMISocketFactory() {
                    public Socket createSocket(String host, int port) throws IOException {
                        Socket socket = new Socket(host, port);
                        socket.setSoTimeout(DEFAULT_RMI_SOCKET_FACTORY_TIMEOUT_MS);
                        socket.setSoLinger(false, 0);
                        return socket;
                    }

                    public ServerSocket createServerSocket(int port) throws IOException {
                        return new ServerSocket(port);
                    }
                });
            } catch (Exception e) {
                log.error("Problem setting custom RMI Socket Factory.", e);
            }

            // TODO: make automatic
            RemoteCacheServerAttributes rcsa = new RemoteCacheServerAttributes();
            rcsa.setConfigFileName(propFile);

            Properties prop = RemoteUtils.loadProps(propFile);
            // Properties prop = PropertyLoader.loadProperties( propFile );

            String servicePortStr = prop.getProperty(REMOTE_CACHE_SERVICE_PORT);
            int servicePort = -1;
            try {
                servicePort = Integer.parseInt(servicePortStr);

                rcsa.setServicePort(servicePort);
                log.debug("Remote cache service uses port number " + servicePort + ".");
            } catch (NumberFormatException ignore) {
                log.debug("Remote cache service port property " + REMOTE_CACHE_SERVICE_PORT
                        + " not specified.  An anonymous port will be used.");
            }

            String lccStr = prop.getProperty(REMOTE_LOCAL_CLUSTER_CONSISTENCY);
            if (lccStr == null) {
                lccStr = "true";
            }
            boolean lcc = Boolean.valueOf(lccStr).booleanValue();
            rcsa.setLocalClusterConsistency(lcc);

            String acgStr = prop.getProperty(REMOTE_ALLOW_CLUSTER_GET);
            if (acgStr == null) {
                acgStr = "true";
            }
            boolean acg = Boolean.valueOf(acgStr).booleanValue();
            rcsa.setAllowClusterGet(acg);

            if (log.isInfoEnabled()) {
                log.info("Creating server with these attributes " + rcsa);
            }

            // CREATE SERVER
            remoteCacheServer = new RemoteCacheServer(rcsa);

            if (host == null) {
                host = "";
            }
            // Register the RemoteCacheServer remote object in the registry.
            serviceName = prop.getProperty(REMOTE_CACHE_SERVICE_NAME, REMOTE_CACHE_SERVICE_VAL).trim();

            if (log.isInfoEnabled()) {
                log.info("Binding server to " + host + ":" + port + " with the name " + serviceName);
            }
            try {
                Naming.rebind("//" + host + ":" + port + "/" + serviceName, remoteCacheServer);
            } catch (MalformedURLException ex) {
                // impossible case.
                throw new IllegalArgumentException(ex.getMessage() + "; host=" + host + ", port=" + port);
            }
        }
    }

    /**
     * Unbinds the remote server.
     * <p>
     * @param host
     * @param port
     * @exception IOException
     */
    static void shutdownImpl(String host, int port) throws IOException {
        if (remoteCacheServer == null) {
            return;
        }
        synchronized (RemoteCacheServer.class) {
            if (remoteCacheServer == null) {
                return;
            }
            log.info("Unbinding host=" + host + ", port=" + port + ", serviceName=" + serviceName);
            try {
                Naming.unbind("//" + host + ":" + port + "/" + serviceName);
            } catch (MalformedURLException ex) {
                // impossible case.
                throw new IllegalArgumentException(
                        ex.getMessage() + "; host=" + host + ", port=" + port + ", serviceName=" + serviceName);
            } catch (NotBoundException ex) {
                // ignore.
            }
            remoteCacheServer.release();
            remoteCacheServer = null;
            // TODO: safer exit ?
            try {
                Thread.sleep(2000);
            } catch (InterruptedException ex) {
                // swallow
            }
            System.exit(0);
        }
    }

    /**
     * Creates an local RMI registry on the default port, starts up the remote cache server, and
     * binds it to the registry.
     * A remote cache is either a local cache or a cluster cache
     * @param args The command line arguments
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        Properties prop = args.length > 0 ? RemoteUtils.loadProps(args[args.length - 1]) : new Properties();

        int port;
        try {
            port = Integer.parseInt(prop.getProperty("registry.port"));
        } catch (NumberFormatException ex) {
            port = Registry.REGISTRY_PORT;
        }

        // shutdown
        if (args.length > 0 && args[0].toLowerCase().indexOf("-shutdown") != -1) {
            String serviceName = prop.getProperty(REMOTE_CACHE_SERVICE_NAME, REMOTE_CACHE_SERVICE_VAL).trim();
            String registry = "//:" + port + "/" + serviceName;

            if (log.isDebugEnabled()) {
                log.debug("looking up server " + registry);
            }
            Object obj = Naming.lookup(registry);
            if (log.isDebugEnabled()) {
                log.debug("server found");
            }
            IRemoteCacheServiceAdmin admin = (IRemoteCacheServiceAdmin) obj;
            try {
                admin.shutdown();
            } catch (Exception ex) {
                log.error("Problem calling shutdown.", ex);
            }
            log.debug("done.");
            System.exit(0);
        }

        // STATS
        if (args.length > 0 && args[0].toLowerCase().indexOf("-stats") != -1) {

            log.debug("getting cache stats");

            try {
                String serviceName = prop.getProperty(REMOTE_CACHE_SERVICE_NAME, REMOTE_CACHE_SERVICE_VAL).trim();
                String registry = "//:" + port + "/" + serviceName;
                log.debug("looking up server " + registry);
                Object obj = Naming.lookup(registry);
                log.debug("server found");

                log.debug("obj = " + obj);
                IRemoteCacheServiceAdmin admin = (IRemoteCacheServiceAdmin) obj;

                try {
                    System.out.println(admin.getStats().toString());
                    log.debug(admin.getStats());
                } catch (Exception es) {
                    log.error(es);
                }

            } catch (Exception ex) {
                log.error("Problem getting stats.", ex);
            }
            log.debug("done.");
            System.exit(0);
        }

        // startup.
        String host = prop.getProperty("registry.host");

        if (host == null || host.trim().equals("") || host.trim().equals("localhost")) {
            log.debug("main> creating registry on the localhost");
            port = RemoteUtils.createRegistry(port);
        }
        log.debug("main> starting up RemoteCacheServer");
        RemoteCacheServerFactory.startup(host, port, args.length > 0 ? args[0] : null);
        log.debug("main> done");
    }
}