Package com.sun.enterprise.admin.cli.cluster

Source Code of com.sun.enterprise.admin.cli.cluster.LocalInstanceCommand

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2013 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License").  You
* may not use this file except in compliance with the License.  You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt.  See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license."  If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above.  However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package com.sun.enterprise.admin.cli.cluster;

import com.sun.enterprise.admin.cli.remote.RemoteCLICommand;
import com.sun.enterprise.util.StringUtils;
import com.sun.enterprise.util.io.FileUtils;
import com.sun.enterprise.util.io.InstanceDirs;
import java.io.*;
import java.io.File;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.*;
import java.util.logging.Level;

import org.glassfish.api.Param;
import org.glassfish.api.admin.*;

import com.sun.enterprise.admin.servermgmt.cli.LocalServerCommand;
import com.sun.enterprise.util.SystemPropertyConstants;
import com.sun.enterprise.util.net.NetUtils;
import com.sun.enterprise.universal.io.SmartFile;
import com.sun.enterprise.util.io.ServerDirs;

/**
* A base class for local commands that manage a local server instance.
* This base class is used by a LOT of other classes.  There is a big comment before
* each section of the file -- sorted by visibility.
* If you specifically want a method to be overridden -- make it protected but
* not final.
* final protected means -- "call me but don't override me".  This convention is
* to make things less confusing.
* If you add a method or change whether it is final -- move it to the right section.
*
* Default instance file structure.
* ||---- <GlassFish Install Root>
*          ||---- nodes (nodeDirRoot, --nodedir)
*                  ||---- <node-1> (nodeDirChild, --node)
*                          || ---- agent
*                                  || ---- config
*                                          | ---- das.properties
*                          || ---- <instance-1> (instanceDir)
*                                  ||---- config
*                                  ||---- applications
*                                  ||---- java-web-start
*                                  ||---- generated
*                                  ||---- lib
*                                  ||---- docroot
*                          || ---- <instance-2> (instanceDir)
*                  ||---- <node-2> (nodeDirChild)
*
* @author Byron Nevins
*/
// -----------------------------------------------------------------------
// ----------------   public methods here   --------------- --------------
// -----------------------------------------------------------------------
public abstract class LocalInstanceCommand extends LocalServerCommand {
    @Param(name = "nodedir", optional = true, alias = "agentdir")
    protected String nodeDir;           // nodeDirRoot
    @Param(name = "node", optional = true, alias = "nodeagent")
    protected String node;
    // subclasses decide whether it's optional, required, or not allowed
    //@Param(name = "instance_name", primary = true, optional = true)
    protected String instanceName;
    protected File nodeDirRoot;         // the parent dir of all node(s)
    protected File nodeDirChild;        // the specific node dir
    protected File instanceDir;         // the specific instance dir
    protected String domainName;
    protected boolean isCreateInstanceFilesystem = false;
    private InstanceDirs instanceDirs;

    // This is especially used for change-master-password command for a node.
    // We iterate through all the instances and so it should relax this requirement,
    // that there is only 1 instance in a node.
    protected boolean checkOneAndOnly = true;

    @Override
    protected void validate()
            throws CommandException, CommandValidationException {
        initInstance();
    }

// -----------------------------------------------------------------------
// -------- protected methods where overriding is allowed here -----------
// -----------------------------------------------------------------------
    /**
     * Override this method if your class does NOT want to create directories
     * @param f the directory to create
     */
    protected boolean mkdirs(File f) {
        return f.mkdirs();
    }

    /**
     * Override this method if your class does NOT want CommandException thrown
     * if directory does not exist.
     * @param f directory to check
     */
    protected boolean isDirectory(File f) {
        return f.isDirectory();
    }

    /**
     * Override this method if your class does NOT want to set ServerDirs
     */
    protected boolean setServerDirs() {
        return true;
    }

    protected void initInstance() throws CommandException {
        /* node dir - parent directory of all node(s) */
        String nodeDirRootPath = null;
        if (ok(nodeDir))
            nodeDirRootPath = nodeDir;
        else // node dir = <install-root>/nodes
            nodeDirRootPath = getNodeDirRootDefault();

        nodeDirRoot = new File(nodeDirRootPath);
        mkdirs(nodeDirRoot);

        if (ok(nodeDir)) {
            // Ensure later uses of nodeDir get an absolute path
            // See bug 15014. Don't use getCanonicalPath(). See bug
            // 15889
            nodeDir = nodeDirRoot.getAbsolutePath();
        }

        if (!isDirectory(nodeDirRoot)) {
            throw new CommandException(
                    Strings.get("Instance.badNodeDir", nodeDirRoot));
        }

        /* <node_dir>/<node> */
        if (node != null) {
            nodeDirChild = new File(nodeDirRoot, node);
        }
        else {
            nodeDirChild = getTheOneAndOnlyNode(nodeDirRoot);
        }

        /* <node_dir>/<node>/<instance name> */
        if (getInstanceName() != null) {
            instanceDir = new File(nodeDirChild, getInstanceName());
            mkdirs(instanceDir);
        }
        else {
            instanceDir = getTheOneAndOnlyInstance(nodeDirChild);
            setInstanceName(instanceDir.getName());
        }

        if (!isDirectory(instanceDir)) {
            throw new CommandException(
                    Strings.get("Instance.badInstanceDir", instanceDir));
        }
        nodeDirChild = SmartFile.sanitize(nodeDirChild);
        instanceDir = SmartFile.sanitize(instanceDir);

        try {
            if (setServerDirs()) {
                instanceDirs = new InstanceDirs(instanceDir);
                setServerDirs(instanceDirs.getServerDirs());
                //setServerDirs(instanceDirs.getServerDirs(), checkForSpecialFiles());
            }
        }
        catch (IOException e) {
            throw new CommandException(e);
        }

        logger.log(Level.FINER, "nodeDirChild: {0}", nodeDirChild);
        logger.log(Level.FINER, "instanceDir: {0}", instanceDir);
    }

    protected final InstanceDirs getInstanceDirs() {
        return instanceDirs;
    }

// -----------------------------------------------------------------------
// -------- protected methods where overriding is NOT allowed here -----------
// -----------------------------------------------------------------------
    /**
     * Set the programOpts based on the das.properties file.
     */
    protected final void setDasDefaults(File propfile) throws CommandException {
        Properties dasprops = getDasProperties(propfile);

        // read properties and set them in programOpts
        // properties are:
        // agent.das.port
        // agent.das.host
        // agent.das.isSecure
        // agent.das.user           XXX - not in v2?
        String p;
        p = dasprops.getProperty("agent.das.host");
        if (p != null) {
            programOpts.setHost(p);
        }
        p = dasprops.getProperty("agent.das.port");
        int port = -1;
        if (p != null) {
            port = Integer.parseInt(p);
        }
        p = dasprops.getProperty("agent.das.protocol");
        if (p != null && p.equals("rmi_jrmp")) {
            programOpts.setPort(updateDasPort(dasprops, port, propfile));
        } else if (p == null || p.equals("http")) {
            programOpts.setPort(port);
        } else {
            throw new CommandException(Strings.get("Instance.badProtocol",
                    propfile.toString(), p));
        }
        p = dasprops.getProperty("agent.das.isSecure");
        if (p != null) {
            programOpts.setSecure(Boolean.parseBoolean(p));
        }
        p = dasprops.getProperty("agent.das.user");
        if (p != null) {
            programOpts.setUser(p);
        }
        // XXX - what about the DAS admin password?
    }

    /**
     * Checks if programOpts values match das.properties file.
     */
    protected final void validateDasOptions(String hostOption, String portOption,
            String isSecureOption, File propfile) throws CommandException {
        if (propfile != null) {
            Properties dasprops = getDasProperties(propfile);
            if (!dasprops.isEmpty()) {
                String errorMsg = "";
                String nodeName = nodeDirChild != null ? nodeDirChild.getName() : "";
                String hostProp = dasprops.getProperty("agent.das.host");
                String portProp = dasprops.getProperty("agent.das.port");
                String secureProp = dasprops.getProperty("agent.das.isSecure");
                if (!matchingHostnames(hostProp, hostOption)) {
                    errorMsg = errorMsg + Strings.get("Instance.DasHostInvalid", hostOption, nodeName) + "\n";
                }
                if (portProp != null && !portProp.equals(portOption)) {
                    errorMsg = errorMsg + Strings.get("Instance.DasPortInvalid", portOption, nodeName) + "\n";
                }
                if (secureProp != null && !secureProp.equals(isSecureOption)) {
                    errorMsg = errorMsg + Strings.get("Instance.DasIsSecureInvalid", isSecureOption, nodeName) + "\n";
                }
                if (!errorMsg.isEmpty()) {
                    errorMsg = errorMsg + Strings.get("Instance.DasConfig", nodeName, hostProp, portProp, secureProp);
                    throw new CommandException(errorMsg);
                }
            }
        }
    }

   /**
     * Check if two hostnames refer to the same host. We start with a cheap
     * string comparison. If that fails we see if the hostnames refer to the
     * same host.
     *
     * @param host1
     * @param host2
     * @return
     */
    private boolean matchingHostnames(String host1, String host2) {

        if (!StringUtils.ok(host1) || !StringUtils.ok(host2)) {
            if (!StringUtils.ok(host1) && !StringUtils.ok(host2)) {
                // Both empty/null strings. Consider it a match.
                return true;
            } else {
                // Only one string null/empty. No match.
                return false;
            }
        }

        if (host1.equalsIgnoreCase(host2)) {
            // Hostnames exactly match. Same host.
            return true;
        }

        if (NetUtils.isEqual(host1, host2)) {
            // Hostnames don't exactly match, but refer to same IP. Match.
            return true;
        }

        if (NetUtils.isThisHostLocal(host1) && NetUtils.isThisHostLocal(host2)) {
            // Hostnames both refer to the local host. Match.
            return true;
        }

        // Don't match.
        return false;
    }

    final protected Properties getDasProperties(File propfile) throws CommandException {
        Properties dasprops = new Properties();
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(propfile);
            dasprops.load(fis);
            fis.close();
            fis = null;
        } catch (IOException ioex) {
            throw new CommandException(
                    Strings.get("Instance.cantReadDasProperties",
                    propfile.getPath()));
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException cex) {
                    // ignore it
                }
            }
        }
        return dasprops;
    }

    final protected void whackFilesystem() throws CommandException {
        ServerDirs dirs = getServerDirs();
        File whackee = dirs.getServerDir();
        File parent = dirs.getServerParentDir();
        File grandParent = dirs.getServerGrandParentDir();

        if (whackee == null || !whackee.isDirectory()) {
            throw new CommandException(Strings.get("DeleteInstance.noWhack",
                    whackee));
        }

        // IT 12680 -- perhaps a new empty dir was created.  Get rid of it and
        // make this an error.
        File[] files = whackee.listFiles();

        if (files == null || files.length <= 0) {
            // empty dir
            if (files != null)
                FileUtils.whack(whackee);

            throw new CommandException(Strings.get("DeleteInstance.noWhack",
                    whackee));
        }

        // Rename the instance directory to a temporary name to ensure that
        // the directory tree can be deleted on Windows.
        // The FileUtils.renameFile method has a retry built in.
        try {
            File tmpwhackee = File.createTempFile("oldinst", null, parent);
            if (!tmpwhackee.delete()) {
                throw new IOException(Strings.get("cantdelete", tmpwhackee));
            }
            FileUtils.renameFile(whackee, tmpwhackee);
            FileUtils.whack(tmpwhackee);
        }
        catch (IOException ioe) {
            throw new CommandException(Strings.get("DeleteInstance.badWhackWithException",
                    whackee, ioe, StringUtils.getStackTrace(ioe)));
        }
        if (whackee.isDirectory()) {
            StringBuilder sb = new StringBuilder();
            sb.append("whackee=").append(whackee.toString());
            sb.append(", files in parent:");
            files = parent.listFiles();
            for (File f : files)
                sb.append(f.toString()).append(", ");
            File f1 = new File(whackee.toString());
            sb.append(", new wackee.exists=").append(f1.exists());
            throw new CommandException(Strings.get("DeleteInstance.badWhack",
                    whackee) + ", " + sb.toString());
        }

        // now see if the parent dir is empty.  If so wipe it out.
        // Don't be too picky with throwin errors here...
        try {
            files = parent.listFiles();

            if (noInstancesRemain(files)) {
                File tmpwhackee = File.createTempFile("oldnode", null, grandParent);
                if (!tmpwhackee.delete()) {
                    throw new IOException(Strings.get("cantdelete", tmpwhackee));
                }
                FileUtils.renameFile(parent, tmpwhackee);
                FileUtils.whack(tmpwhackee);
            }
        }
        catch (IOException ioe) {
            // we tried!!!
        }
    }

    private boolean noInstancesRemain(File[] files) {
        if (files == null || files.length <= 0)
            return true;

        if (files.length == 1
                && files[0].isDirectory()
                && files[0].getName().equals("agent"))
            return true;

        return false;
    }

    /**
     * Gets the GlassFish installation root (using property com.sun.aas.installRoot),
     * first from asenv.conf.  If that's not available, then from java.lang.System.
     *
     * @return path of GlassFish install root
     * @throws CommandException if the GlassFish install root is not found
     */
    protected String getInstallRootPath() throws CommandException {
        String installRootPath = getSystemProperty(
                SystemPropertyConstants.INSTALL_ROOT_PROPERTY);

        if (!StringUtils.ok(installRootPath))
            installRootPath = System.getProperty(
                    SystemPropertyConstants.INSTALL_ROOT_PROPERTY);

        if (!StringUtils.ok(installRootPath))
            throw new CommandException("noInstallDirPath");
        return installRootPath;
    }

    /**
     * Gets the GlassFish product installation root (using property
     * com.sun.aas.productRoot), first from asenv.conf. If that's not
     * available, then from java.lang.System.
     *
     * This will typically be the parent of the glassfish install root
     *
     * @return path of GlassFish product install root
     * @throws CommandException if the GlassFish install root is not found
     */
    protected String getProductRootPath() throws CommandException {
        String productRootPath = getSystemProperty(
                SystemPropertyConstants.PRODUCT_ROOT_PROPERTY);

        if (!StringUtils.ok(productRootPath))
            productRootPath = System.getProperty(
                    SystemPropertyConstants.PRODUCT_ROOT_PROPERTY);

        if (!StringUtils.ok(productRootPath)) {
            // Product install root is parent of glassfish install root
            File installRoot = new File(getInstallRootPath());
            return installRoot.getParent();
        }
        return productRootPath;
    }

    protected String getNodeInstallDir() throws CommandException {
        String installDir = null;
        try {
            RemoteCLICommand rc = new RemoteCLICommand("get", this.programOpts, this.env);
            String s = rc.executeAndReturnOutput("get", "nodes.node." + node + ".install-dir");
            if (s != null) {
                installDir = s.substring(s.indexOf('=') + 1);
            }
        } catch (CommandException ce) {
            // ignore
        }
        return installDir;
    }

// -----------------------------------------------------------------------
// -------- everything below here is private    --------------------------
// -----------------------------------------------------------------------
    /**
     * Update DAS port from an old V2 das.properties file.
     * If the old port is the standard jrmp port, just use the new
     * standard http port.  Otherwise, prompt for the new port number
     * if possible.  In any event, try to rewrite the das.properties
     * file with the new values.
     */
    private int updateDasPort(Properties dasprops, int port, File propfile) {
        Console cons;
        if (port == 8686) {     // the old JRMP port
            logger.info(
                    Strings.get("Instance.oldDasProperties",
                    propfile.toString(), Integer.toString(port),
                    Integer.toString(programOpts.getPort())));
            port = programOpts.getPort();
        }
        else if ((cons = System.console()) != null) {
            String line = cons.readLine("%s",
                    Strings.get("Instance.oldDasPropertiesPrompt",
                    propfile.toString(), Integer.toString(port),
                    Integer.toString(programOpts.getPort())));
            while (line != null && line.length() > 0) {
                try {
                    port = Integer.parseInt(line);
                    if (port > 0 && port <= 65535)
                        break;
                }
                catch (NumberFormatException nfex) {
                }
                line = cons.readLine(Strings.get("Instance.reenterPort"),
                        Integer.toString(programOpts.getPort()));
            }
        }
        else {
            logger.info(
                    Strings.get("Instance.oldDasPropertiesWrong",
                    propfile.toString(), Integer.toString(port),
                    Integer.toString(programOpts.getPort())));
            port = programOpts.getPort();
        }
        dasprops.setProperty("agent.das.protocol", "http");
        dasprops.setProperty("agent.das.port", Integer.toString(port));
        BufferedOutputStream bos = null;
        try {
            bos = new BufferedOutputStream(new FileOutputStream(propfile));
            dasprops.store(bos,
                    "Domain Administration Server Connection Properties");
            bos.close();
            bos = null;
        }
        catch (IOException ex2) {
            logger.info(
                    Strings.get("Instance.dasPropertiesUpdateFailed"));
        }
        finally {
            if (bos != null) {
                try {
                    bos.close();
                }
                catch (IOException cex) {
                    // ignore it
                }
            }
        }
        // whether we were able to update the file or not, keep going
        logger.log(Level.FINER, "New DAS port number: {0}", port);
        return port;
    }

    private File getTheOneAndOnlyNode(File parent) throws CommandException {
        // look for subdirs in the parent dir -- there must be one and only one
        // or there can be zero in which case we create one-and-only

        File[] files = parent.listFiles(new FileFilter() {
            @Override
            public boolean accept(File f) {
                return isDirectory(f);
            }
        });

        // ERROR:  more than one node dir child
        if (files != null && files.length > 1) {
            throw new CommandException(
                    Strings.get("tooManyNodes", parent));
        }

        // the usual case -- one node dir child
        if (files != null && files.length == 1)
            return files[0];

        /*
         * If there is no existing node dir child -- create one!
         * If the instance is on the same machine as DAS, use "localhost" as the node dir child
         * Only for _create-instance-filesystem
         */
        if (isCreateInstanceFilesystem) {
            try {
                String dashost = null;
                if (programOpts != null) {
                    dashost = programOpts.getHost();
                }
                String hostname = InetAddress.getLocalHost().getHostName();
                if (hostname.equals(dashost) || NetUtils.isThisHostLocal(dashost)) {
                    hostname = "localhost" + "-" + domainName;
                }
                File f = new File(parent, hostname);

                if (!(mkdirs(f) || isDirectory(f))) // for instance there is a regular file with that name
                {
                    throw new CommandException(Strings.get("cantCreateNodeDirChild", f));
                }

                return f;
            } catch (UnknownHostException ex) {
                throw new CommandException(Strings.get("cantGetHostName", ex));
            }
        } else {
            throw new CommandException(Strings.get("DeleteInstance.noInstance"));
        }
    }

    private File getTheOneAndOnlyInstance(File parent) throws CommandException {
        // look for subdirs in the parent dir -- there must be one and only one

        File[] files = parent.listFiles(new FileFilter() {
            @Override
            public boolean accept(File f) {
                return isDirectory(f);
            }
        });

        if (files == null || files.length == 0) {
            throw new CommandException(
                    Strings.get("Instance.noInstanceDirs", parent));
        }

        // expect two - the "agent" directory and the instance directory
        if (files.length > 2 && checkOneAndOnly) {
            throw new CommandException(
                    Strings.get("Instance.tooManyInstanceDirs", parent));
        }

        for (File f : files) {
            if (!f.getName().equals("agent"))
                return f;
        }
        throw new CommandException(
                Strings.get("Instance.noInstanceDirs", parent));
    }

    /**
     * Return the default value for nodeDirRoot, first checking if com.sun.aas.agentRoot
     * was specified in asenv.conf and returning this value. If not specified,
     * then the defaut value is the {GlassFish_Install_Root}/nodes.
     * nodeDirRoot is the parent directory of the node(s).
     *
     * @return String default nodeDirRoot - parent directory of node(s)
     * @throws CommandException if the GlassFish install root is not found
     */
    private String getNodeDirRootDefault() throws CommandException {
        String nodeDirDefault = getSystemProperty(
                SystemPropertyConstants.AGENT_ROOT_PROPERTY);

        if (StringUtils.ok(nodeDirDefault))
            return nodeDirDefault;

        String installRootPath = getInstallRootPath();
        return installRootPath + "/" + "nodes";
    }

    @Override
    protected File getMasterPasswordFile() {

        if (nodeDirChild == null)
            return null;

        File mp = new File(new File(nodeDirChild,"agent"), "master-password");
        if (!mp.canRead())
            return null;

        return mp;
    }

    /**
     * @return the instanceName
     */
    public String getInstanceName() {
        return instanceName;
    }

    /**
     * @param instanceName the instanceName to set
     */
    public void setInstanceName(String instanceName) {
        this.instanceName = instanceName;
    }
}
TOP

Related Classes of com.sun.enterprise.admin.cli.cluster.LocalInstanceCommand

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.