org.hyperic.hq.bizapp.agent.server.CommandsServer.java Source code

Java tutorial

Introduction

Here is the source code for org.hyperic.hq.bizapp.agent.server.CommandsServer.java

Source

/*
 * NOTE: This copyright does *not* cover user programs that use HQ
 * program services by normal system calls through the application
 * program interfaces provided as part of the Hyperic Plug-in Development
 * Kit or the Hyperic Client Development Kit - this is merely considered
 * normal use of the program, and does *not* fall under the heading of
 * "derived work".
 * 
 * Copyright (C) [2004, 2005, 2006], Hyperic, Inc.
 * This file is part of HQ.
 * 
 * HQ is free software; you can redistribute it and/or modify
 * it under the terms version 2 of the GNU General Public License as
 * published by the Free Software Foundation. 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA.
 */

package org.hyperic.hq.bizapp.agent.server;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.util.Properties;

import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hyperic.hq.agent.AgentAPIInfo;
import org.hyperic.hq.agent.AgentConfig;
import org.hyperic.hq.agent.AgentConfigException;
import org.hyperic.hq.agent.AgentKeystoreConfig;
import org.hyperic.hq.agent.AgentRemoteException;
import org.hyperic.hq.agent.AgentRemoteValue;
import org.hyperic.hq.agent.AgentStartupCallback;
import org.hyperic.hq.agent.server.AgentDaemon;
import org.hyperic.hq.agent.server.AgentNotificationHandler;
import org.hyperic.hq.agent.server.AgentServerHandler;
import org.hyperic.hq.agent.server.AgentStartException;
import org.hyperic.hq.agent.server.AgentStorageException;
import org.hyperic.hq.agent.server.AgentStorageProvider;
import org.hyperic.hq.bizapp.agent.CommandsAPIInfo;
import org.hyperic.hq.bizapp.agent.ProviderInfo;
import org.hyperic.hq.bizapp.agent.TokenData;
import org.hyperic.hq.bizapp.agent.TokenManager;
import org.hyperic.hq.bizapp.agent.TokenStorer;
import org.hyperic.hq.bizapp.agent.commands.CreateToken_args;
import org.hyperic.hq.bizapp.agent.commands.CreateToken_result;
import org.hyperic.hq.bizapp.agent.commands.GetServer_args;
import org.hyperic.hq.bizapp.agent.commands.GetServer_result;
import org.hyperic.hq.bizapp.agent.commands.SetServer_args;
import org.hyperic.hq.bizapp.agent.commands.SetServer_result;
import org.hyperic.util.security.KeystoreConfig;
import org.hyperic.util.security.KeystoreManager;
import org.hyperic.util.security.SecurityUtil;

public class CommandsServer implements AgentServerHandler, TokenStorer, AgentNotificationHandler {
    private static final long TOKEN_TIMEOUT = 20 * 1000; // 20 seconds

    private CommandsAPIInfo verAPI;
    private Log log;
    private TokenManager tokenManager;
    private AgentStorageProvider storage;
    private AgentDaemon agent;
    private Socket startupSock;
    private String tokenFile;
    private String keyAlg;
    private AgentStartupCallback agentStartupCallback;

    public CommandsServer() {
        this.verAPI = new CommandsAPIInfo();
        this.log = LogFactory.getLog(CommandsServer.class);
        this.tokenManager = null;
        this.storage = null;
        this.agent = null;
        this.startupSock = null;
        this.keyAlg = null;
        this.agentStartupCallback = null;
    }

    public AgentAPIInfo getAPIInfo() {
        return this.verAPI;
    }

    public String[] getCommandSet() {
        return CommandsAPIInfo.commandSet;
    }

    public AgentRemoteValue dispatchCommand(String cmd, AgentRemoteValue args, InputStream in, OutputStream out)
            throws AgentRemoteException {
        if (cmd.equals(CommandsAPIInfo.command_createToken)) {
            return this.createToken(new CreateToken_args(args));
        } else if (cmd.equals(CommandsAPIInfo.command_getServer)) {
            return this.getServer(new GetServer_args(args));
        } else if (cmd.equals(CommandsAPIInfo.command_setServer)) {
            return this.setServer(new SetServer_args(args));
        } else {
            throw new AgentRemoteException("Unknown command: " + cmd);
        }
    }

    private String getTokenFile() {
        return this.tokenFile;
    }

    public OutputStream getTokenStoreStream() throws IOException {
        return new FileOutputStream(getTokenFile());
    }

    private void storeTokens() throws IOException {
        try {
            this.tokenManager.store();
        } catch (IOException exc) {
            this.log.error("Failed to store token data to '" + getTokenFile() + "': " + exc.getMessage());
            throw exc;
        }
    }

    private CreateToken_result createToken(CreateToken_args args) {
        CreateToken_result res;
        TokenData newToken;

        newToken = new TokenData(SecurityUtil.generateRandomToken(), System.currentTimeMillis(), false);
        res = new CreateToken_result();
        res.setToken(newToken.getToken());
        this.tokenManager.addToken(newToken);
        try {
            this.storeTokens();
        } catch (IOException exc) {
            // ignore, since there is nothing we can do
        }
        return res;
    }

    private SetServer_result setServer(SetServer_args args) {
        SetServer_result res;
        ProviderInfo provider;

        provider = args.getProvider();

        String providerMsg = "Setting the HQ server to: " + provider.getProviderAddress();

        if (provider.isNewTransport()) {
            providerMsg += "; unidirectional=" + provider.isUnidirectional();
        }

        this.log.info(providerMsg);

        CommandsAPIInfo.setProvider(this.storage, provider);
        try {
            this.storage.flush();
        } catch (AgentStorageException exc) {
            this.log.error("Error flushing storage", exc);
        }
        res = new SetServer_result();

        this.agent.sendNotification(CommandsAPIInfo.NOTIFY_SERVER_SET, provider.getProviderAddress());
        return res;
    }

    private GetServer_result getServer(GetServer_args args) {
        GetServer_result res;
        ProviderInfo provider;

        res = new GetServer_result();
        res.setProvider(CommandsAPIInfo.getProvider(this.storage));
        return res;
    }

    private KeyStore getKeyStoreInstance() throws AgentStartException {
        final String KEYSTORE_TYPE = "JKS";

        try {
            return KeyStore.getInstance(KEYSTORE_TYPE);
        } catch (KeyStoreException exc) {
            throw new AgentStartException("Unable to get keystore instance " + "for " + KEYSTORE_TYPE);
        }
    }

    private KeyManager[] getKeyManagers(KeyStore useStore, String filePass) throws AgentStartException {
        KeyManagerFactory res;
        String alg;

        alg = KeyManagerFactory.getDefaultAlgorithm();
        try {
            res = KeyManagerFactory.getInstance(alg);
            res.init(useStore, filePass.toCharArray());
        } catch (Exception exc) {
            throw new AgentStartException("Unable to get default key " + "manager: " + exc.getMessage());
        }
        return res.getKeyManagers();
    }

    private TokenData generateLocalToken(AgentConfig cfg) throws AgentStartException {
        InetAddress addr;

        try {
            if ((addr = cfg.getListenIpAsAddr()) == null) {
                //XXX InetAddress.getByAddress is only in jdk 1.4+
                addr = InetAddress.getByName("127.0.0.1");
            }
        } catch (Exception exc) {
            throw new AgentStartException("Unable to get listen IP as addr: " + exc.getMessage());
        }

        return new TokenData(SecurityUtil.generateRandomToken(), System.currentTimeMillis(), true);
    }

    private void setupTokenManager(AgentConfig cfg) throws AgentStartException {
        String tokenFile = getTokenFile();

        this.tokenManager = new TokenManager(TOKEN_TIMEOUT, this);
        try {
            this.tokenManager.load(new FileInputStream(tokenFile));
        } catch (IOException exc) {
            this.log.warn("Unable to load " + tokenFile + ": generating " + "new file: " + exc.getMessage());
            this.tokenManager.addToken(this.generateLocalToken(cfg));
            try {
                this.storeTokens();
            } catch (IOException eExc) {
                final String msg = "Unable to store " + tokenFile + ": " + eExc.getMessage();

                throw new AgentStartException(msg);
            }
        }
    }

    public void handleNotification(String msgClass, String msg) {
        this.log.debug("handling notification: " + msgClass + ":" + msg);

        if (this.agentStartupCallback != null) {
            this.log.debug("calling back to agent");
            if (msgClass.equals(AgentDaemon.NOTIFY_AGENT_UP)) {
                this.agentStartupCallback.onAgentStartup(true);
            } else if (msgClass.equals(AgentDaemon.NOTIFY_AGENT_FAILED_START)) {
                this.agentStartupCallback.onAgentStartup(false);
            }
        }

    }

    public void startup(AgentDaemon agent) throws AgentStartException {
        try {
            this.agentStartupCallback = new AgentStartupCallback(agent.getBootConfig());
            agent.registerNotifyHandler(this, AgentDaemon.NOTIFY_AGENT_UP);
            agent.registerNotifyHandler(this, AgentDaemon.NOTIFY_AGENT_FAILED_START);
        } catch (AgentConfigException e) {
            log.warn("Failure to find startup reporting port in sys properties: " + e);
            log.debug(e, e);
        } catch (IOException e) {
            throw new AgentStartException("Wrapped Exception", e);
        }

        this.agent = agent;

        try {
            SSLConnectionListener listener;
            KeyManager[] keyManagers;
            AgentConfig cfg;
            Properties bootConfig;
            KeyStore keystore;

            cfg = agent.getBootConfig();
            this.tokenFile = cfg.getTokenFile();
            this.setupTokenManager(cfg);
            bootConfig = cfg.getBootProperties();
            this.storage = agent.getStorageProvider();
            this.keyAlg = bootConfig.getProperty("agent.keyalg", "RSA");

            KeystoreConfig keystoreConfig = new AgentKeystoreConfig();
            keystore = KeystoreManager.getKeystoreManager().getKeyStore(keystoreConfig);
            keyManagers = this.getKeyManagers(keystore, keystoreConfig.getFilePassword());
            listener = new SSLConnectionListener(cfg, this.tokenManager);
            agent.setConnectionListener(listener);
        } catch (Exception exc) {
            //This catch is intended to catch AgentRunningException, KeyStoreException, IOException
            throw new AgentStartException("Unable to initialize SSL: " + exc.getMessage(), exc);
        }
        this.log.info("Commands Server started up");
    }

    public final void postInitActions() throws AgentStartException {
        /*do nothing*/ }//EOM

    public void shutdown() {
        this.log.info("Commands Server shut down");
    }
}