net.wimpi.telnetd.shell.ShellManager.java Source code

Java tutorial

Introduction

Here is the source code for net.wimpi.telnetd.shell.ShellManager.java

Source

//License
/***
 * Java TelnetD library (embeddable telnet daemon)
 * Copyright (c) 2000-2005 Dieter Wimberger 
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * Neither the name of the author nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *  
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS
 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 * POSSIBILITY OF SUCH DAMAGE.
 ***/

package net.wimpi.telnetd.shell;

import net.wimpi.telnetd.BootException;
import net.wimpi.telnetd.util.StringUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Properties;

/**
 * This class implements a Manager Singleton that takes care
 * for all shells to be offered.<br>
 * <p/>
 * The resources can be defined via properties that contain following
 * information:
 * <ul>
 * <li> All system defined shells:
 * <ol>
 * <li>Login: first shell run on top of the connection.
 * <li>Queue: shell thats run for connections placed into the queue.
 * <li>Admin: shell for administrative tasks around the embedded telnetd.
 * </ol>
 * <li> Custom defined shells:<br>
 * Declared as value to the <em>customshells</em> key, in form of a comma seperated
 * list of names. For each declared name there has to be an entry defining the shell.
 * </ul>
 * The definition of any shell is simply represented by a fully qualified class name, of a class
 * that implements the shell interface. Please read the documentation of this interface carefully.<br>
 * The properties are passed on creation through the factory method, which is called by the
 * net.wimpi.telnetd.TelnetD class.
 *
 * @author Dieter Wimberger
 * @version 2.0 (16/07/2006)
 * @see net.wimpi.telnetd.shell.Shell
 */
public class ShellManager {

    private static Log log = LogFactory.getLog(ShellManager.class);
    private static ShellManager c_Self; //Singleton reference
    private HashMap shells; //datastructure for shells

    private ShellManager() {
    }//constructor

    /**
     * Private constructor, instance can only be created
     * via the public factory method.
     */
    private ShellManager(HashMap shells) {
        c_Self = this;
        this.shells = new HashMap(shells.size());
        setupShells(shells);
    }//constructor

    /**
     * Accessor method for shells that have been set up.<br>
     * Note that it uses a factory method that any shell should
     * provide via a specific class operation.<br>
     *
     * @param key String that represents a shell name.
     * @return Shell instance that has been obtained from the
     *         factory method.
     */
    public Shell getShell(String key) {
        Shell myShell = null;
        try {
            if (!shells.containsKey(key)) {
                return null;
            }
            Object obj = shells.get(key);
            if (obj instanceof Class) {
                Class shclass = (Class) obj;
                Method factory = shclass.getMethod("createShell", null);
                log.debug("[Factory Method] " + factory.toString());
                myShell = (Shell) factory.invoke(shclass, null);
            }
            if (obj instanceof Shell) {
                myShell = (Shell) obj.getClass().newInstance();
            }
        } catch (Exception e) {
            log.error("getShell()", e);
        }

        return myShell;
    }//getShell

    /**
     * Method to initialize the system and custom shells
     * whose names and classes are stored as keys within the shells.
     * <p/>
     * It allows other initialization routines to prepare
     * shell specific resources. This is a similar procedure
     * as used for Servlets.
     */
    private void setupShells(HashMap shells) {
        String sh = "";
        String shclassstr = "";
        //temporary storage for fully qualified classnames,
        //serves the purpose of not loading classes twice.
        HashMap shellclasses = new HashMap(shells.size());

        for (Iterator iter = shells.keySet().iterator(); iter.hasNext();) {
            try {
                //first we get the key
                sh = (String) iter.next();
                //then the fully qualified shell class string
                Object obj = shells.get(sh);
                if (obj instanceof Shell) {
                    log.debug("shell [" + sh + "] already instanciated");
                    this.shells.put(sh, obj);
                    continue;
                }
                shclassstr = (String) obj;
                log.debug("Preparing Shell [" + sh + "] " + shclassstr);
                //now we check if the class is already loaded.
                //If,then we reference the same class object and thats it
                if (shellclasses.containsKey(shclassstr)) {
                    this.shells.put(sh, shellclasses.get(shclassstr));
                    log.debug("Class [" + shclassstr + "] already loaded, using cached class object.");
                } else {
                    //we get the class object (e.g. load it because its new)
                    Class shclass = Class.forName(shclassstr);
                    //and put it to the shells, plus our "class object cache"
                    this.shells.put(sh, shclass);
                    shellclasses.put(shclassstr, shclass);
                    log.debug("Class [" + shclassstr + "] loaded and class object cached.");
                }
            } catch (Exception e) {
                log.error("setupShells()", e);
            }

        }
    }//setupShells

    /**
     * Factory method for creating the Singleton instance of
     * this class.<br>
     * Note that this factory method is called by the
     * net.wimpi.telnetd.TelnetD class.
     *
     * @param settings Properties defining the shells as described in the
     *                 class documentation.
     * @return ShellManager Singleton instance.
     */
    public static ShellManager createShellManager(Properties settings) throws BootException {

        //Loading and applying settings
        try {
            log.debug("createShellManager()");
            HashMap shells = new HashMap();
            //Custom shell definitions
            String sh = settings.getProperty("shells");
            if (sh != null) {
                String[] customshs = StringUtil.split(sh, ",");
                for (int z = 0; z < customshs.length; z++) {
                    //we get the shell
                    sh = settings.getProperty("shell." + customshs[z] + ".class");
                    if (sh == null) {
                        log.debug("Shell entry named " + customshs[z] + " not found.");
                        throw new BootException("Shell " + customshs[z] + " declared but not defined.");
                    } else {
                        shells.put(customshs[z], sh);
                    }
                }
            }

            //construct manager
            ShellManager shm = new ShellManager(shells);
            return shm;

        } catch (Exception ex) {
            log.error("createManager()", ex);
            throw new BootException("Creating ShellManager Instance failed:\n" + ex.getMessage());
        }
    }//createManager

    /**
     * creates an empty shell manager
     */
    public static ShellManager createShellManager(HashMap shells) {
        ShellManager shm = new ShellManager(shells);
        return shm;
    }

    /**
     * Accessor method for the Singleton instance of this class.<br>
     * Note that it returns null if the instance was not properly
     * created beforehand.
     *
     * @return ShellManager Singleton instance reference.
     */
    public static ShellManager getReference() {
        return c_Self;
    }//getReference

    public HashMap getShells() {
        return shells;
    }

    public void setShells(HashMap shells) {
        this.shells = shells;
    }

}//class ShellManager