org.ow2.proactive.resourcemanager.utils.PAAgentServiceRMStarter.java Source code

Java tutorial

Introduction

Here is the source code for org.ow2.proactive.resourcemanager.utils.PAAgentServiceRMStarter.java

Source

/*
 * ################################################################
 *
 * ProActive Parallel Suite(TM): The Java(TM) library for
 *    Parallel, Distributed, Multi-Core Computing for
 *    Enterprise Grids & Clouds
 *
 * Copyright (C) 1997-2011 INRIA/University of
 *                 Nice-Sophia Antipolis/ActiveEon
 * Contact: proactive@ow2.org or contact@activeeon.com
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License
 * as published by the Free Software Foundation; version 3 of
 * the License.
 *
 * This library 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
 * Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * If needed, contact us to obtain a release under GPL Version 2 or 3
 * or a different license than the AGPL.
 *
 *  Initial developer(s):               The ProActive Team
 *                        http://proactive.inria.fr/team_members.htm
 *  Contributor(s): ActiveEon Team - http://www.activeeon.com
 *
 * ################################################################
 * $$ACTIVEEON_CONTRIBUTOR$$
 */
package org.ow2.proactive.resourcemanager.utils;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.Parser;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.objectweb.proactive.core.node.Node;
import org.objectweb.proactive.core.node.NodeFactory;
import org.ow2.proactive.authentication.crypto.Credentials;
import org.ow2.proactive.resourcemanager.authentication.RMAuthentication;
import org.ow2.proactive.resourcemanager.common.RMConstants;
import org.ow2.proactive.resourcemanager.exception.AddingNodesException;
import org.ow2.proactive.resourcemanager.frontend.RMConnection;
import org.ow2.proactive.resourcemanager.frontend.ResourceManager;

/**
 * This class is responsible for creating a local node and add it
 * to the Resource Manager.
 * 
 * @deprecated use {@link RMNodeStarter} instead
 * @author ProActive team
 */
@Deprecated
public final class PAAgentServiceRMStarter {

    /** The default url of the Resource Manager */
    private static final String DEFAULT_RM_URL = "rmi://localhost:1099/";

    /** The default name of the node */
    private static final String PAAGENT_DEFAULT_NODE_NAME = "PA-AGENT_NODE";

    /** Prefix for temp files that store nodes URL */
    private static final String URL_TMPFILE_PREFIX = "PA-AGENT_URL";

    /** Name of the java property to set the rank */
    private final static String RANK_PROP_NAME = "proactive.agent.rank";

    /** class' logger */
    private static final Logger logger = Logger.getLogger(PAAgentServiceRMStarter.class);

    /**
     * The starter will try to connect to the Resource Manager before killing
     * itself that means that it will try to connect during
     * WAIT_ON_JOIN_TIMEOUT_IN_MS milliseconds
     */
    private static int WAIT_ON_JOIN_TIMEOUT_IN_MS = 60000;
    /**
     * The ping delay used in RMPinger that pings the RM and exists if the
     * Resource Manager is down
     */
    private static long PING_DELAY_IN_MS = 30000;

    /** The number of attempts to add the local node to the RM before quitting */
    private static int NB_OF_ADD_NODE_ATTEMPTS = 10;

    /** The delay, in millis, between two attempts to add a node */
    private static int ADD_NODE_ATTEMPTS_DELAY_IN_MS = 5000;

    // The url of the created node
    private String nodeURL = "Not defined";
    // the rank of this node
    private int rank;
    // if true, previous nodes with different URLs are removed from the RM
    private boolean removePrevious;

    /**
     * Returns the rank of this node
     * @return the rank of this node
     */
    public int getRank() {
        return rank;
    }

    /**
     * Returns the URL of the node handled by this starter.
     * @return the URL of the node handled by this starter.
     */
    public String getNodeURL() {
        return this.nodeURL;
    }

    /**
     * To define the default log4j configuration if log4j.configuration property has not been set.
     */
    public static void checkLog4jConfiguration() {
        try {
            String log4jPath = System.getProperty("log4j.configuration");
            if (log4jPath == null) {
                //either sched-home/dist/lib/PA-RM.jar or sched-home/classes/resource-manager/
                File origin = new File(PAAgentServiceRMStarter.class.getProtectionDomain().getCodeSource()
                        .getLocation().getFile());
                File parent = origin.getParentFile();
                configuration: {
                    while (parent != null && parent.isDirectory()) {
                        File[] childs = parent.listFiles();
                        for (File child : childs) {
                            if ("config".equals(child.getName())) {
                                //we have found the sched-home/config/ directory!
                                log4jPath = child.getAbsolutePath() + File.separator + "log4j" + File.separator
                                        + "log4j-defaultNode";
                                File log4j = new File(log4jPath);
                                if (log4j.exists()) {
                                    URL log4jURL;
                                    try {
                                        log4jURL = log4j.toURL();
                                        PropertyConfigurator.configure(log4jURL);
                                        System.setProperty("log4j.configuration", log4jPath);
                                        logger.trace("log4j.configuration not set, " + log4jPath
                                                + " defiined as default log4j configuration.");
                                    } catch (MalformedURLException e) {
                                        logger.trace("Cannot configure log4j", e);
                                    }
                                } else {
                                    logger.trace("Log4J configuration not found. Cannot configure log4j");
                                }
                                break configuration;
                            }
                        }
                        parent = parent.getParentFile();
                    }
                }
            } else {
                logger.trace("Does not override log4j.configuration");
            }
        } catch (Exception ex) {
            logger.trace("Cannot set log4j Configuration", ex);
        }
    }

    /**
     * Fills the command line options.
     * @param options the options to fill 
     */
    public static void fillOptions(final Options options) {
        // The path to the file that contains the credential
        final Option credentialFile = new Option("f", "credentialFile", true,
                "path to file that contains the credential");
        credentialFile.setRequired(false);
        credentialFile.setArgName("path");
        options.addOption(credentialFile);
        // The credential passed as environment variable
        final Option credentialEnv = new Option("e", "credentialEnv", true,
                "name of the environment variable that contains the credential");
        credentialEnv.setRequired(false);
        credentialEnv.setArgName("name");
        options.addOption(credentialEnv);
        // The credential passed as value
        final Option credVal = new Option("v", "credentialVal", true, "explicit value of the credential");
        credVal.setRequired(false);
        credVal.setArgName("credential");
        options.addOption(credVal);
        // The url of the resource manager
        final Option rmURL = new Option("r", "rmURL", true, "URL of the resource manager");
        rmURL.setRequired(false);
        rmURL.setArgName("url");
        options.addOption(rmURL);
        // The node name
        final Option nodeName = new Option("n", "nodeName", true,
                "node name (default is " + PAAGENT_DEFAULT_NODE_NAME + ")");
        nodeName.setRequired(false);
        nodeName.setArgName("name");
        options.addOption(nodeName);
        // The node source name 
        final Option sourceName = new Option("s", "sourceName", true, "node source name");
        sourceName.setRequired(false);
        sourceName.setArgName("name");
        options.addOption(sourceName);
        // The wait on join timeout in millis
        final Option waitOnJoinTimeout = new Option("w", "waitOnJoinTimeout", true,
                "wait on join the resource manager timeout in millis (default is " + WAIT_ON_JOIN_TIMEOUT_IN_MS
                        + ")");
        waitOnJoinTimeout.setRequired(false);
        waitOnJoinTimeout.setArgName("millis");
        options.addOption(waitOnJoinTimeout);
        // The ping delay in millis
        final Option pingDelay = new Option("p", "pingDelay", true,
                "ping delay in millis used by RMPinger thread that calls System.exit(1) if the resource manager is down (default is "
                        + PING_DELAY_IN_MS + ")");
        pingDelay.setRequired(false);
        pingDelay.setArgName("millis");
        options.addOption(pingDelay);
        // The number of attempts option
        final Option addNodeAttempts = new Option("a", "addNodeAttempts", true,
                "number of attempts to add the local node to the resource manager before quitting (default is "
                        + NB_OF_ADD_NODE_ATTEMPTS + ")");
        addNodeAttempts.setRequired(false);
        addNodeAttempts.setArgName("number");
        options.addOption(addNodeAttempts);
        // The delay between attempts option
        final Option addNodeAttemptsDelay = new Option("d", "addNodeAttemptsDelay", true,
                "delay in millis between attempts to add the local node to the resource manager (default is "
                        + ADD_NODE_ATTEMPTS_DELAY_IN_MS + ")");
        addNodeAttemptsDelay.setRequired(false);
        addNodeAttemptsDelay.setArgName("millis");
        options.addOption(addNodeAttemptsDelay);
        // Displays the help
        final Option help = new Option("h", "help", false, "to display this help");
        help.setRequired(false);
        options.addOption(help);
    }

    /**
     * Creates a new instance of this class and calls registersInRm method.
     * 
     * @param args
     *            The arguments needed to join the Resource Manager
     */
    public static void main(final String args[]) {
        checkLog4jConfiguration();
        Credentials credentials = null;
        String rmURL = PAAgentServiceRMStarter.DEFAULT_RM_URL;
        String nodeName = PAAgentServiceRMStarter.PAAGENT_DEFAULT_NODE_NAME;
        String nodeSourceName = null;
        boolean printHelp = false;

        final Parser parser = new GnuParser();
        final Options options = new Options();
        PAAgentServiceRMStarter.fillOptions(options);
        try {
            // Parse the command line           
            final CommandLine cl = parser.parse(options, args);

            // The path to the file that contains the credential
            if (cl.hasOption('f')) {
                credentials = Credentials.getCredentials(cl.getOptionValue('f'));
                // The name of the env variable that contains     
            } else if (cl.hasOption('e')) {
                final String variableName = cl.getOptionValue('e');
                final String value = System.getenv(variableName);
                if (value == null) {
                    throw new IllegalArgumentException("Unable to read the value of the " + variableName);
                }
                credentials = Credentials.getCredentialsBase64(value.getBytes());
                // Read the credentials directly from the command-line argument   
            } else if (cl.hasOption('v')) {
                final String str = cl.getOptionValue('v');
                credentials = Credentials.getCredentialsBase64(str.getBytes());
            } else {
                credentials = Credentials.getCredentials();
            }
            // Mandatory rmURL option                                
            if (cl.hasOption('r')) {
                rmURL = cl.getOptionValue('r');
            }
            // Optional node name
            if (cl.hasOption('n')) {
                nodeName = cl.getOptionValue('n');
            }
            // Optional node source name
            if (cl.hasOption('s')) {
                nodeSourceName = cl.getOptionValue('s');
            }
            // Optional wait on join option
            if (cl.hasOption('w')) {
                PAAgentServiceRMStarter.WAIT_ON_JOIN_TIMEOUT_IN_MS = Integer.valueOf(cl.getOptionValue('w'));
            }
            // Optional ping delay
            if (cl.hasOption('p')) {
                PAAgentServiceRMStarter.PING_DELAY_IN_MS = Integer.valueOf(cl.getOptionValue('p'));
            }
            // Optional number of add node attempts before quitting
            if (cl.hasOption('a')) {
                PAAgentServiceRMStarter.NB_OF_ADD_NODE_ATTEMPTS = Integer.valueOf(cl.getOptionValue('a'));
            }
            // Optional delay between add node attempts
            if (cl.hasOption('d')) {
                PAAgentServiceRMStarter.ADD_NODE_ATTEMPTS_DELAY_IN_MS = Integer.valueOf(cl.getOptionValue('d'));
            }
            // Optional help option
            if (cl.hasOption('h')) {
                printHelp = true;
            }
        } catch (Throwable t) {
            printHelp = true;
            t.printStackTrace();
            return;
        } finally {
            if (printHelp) {
                // Automatically generate the help statement
                HelpFormatter formatter = new HelpFormatter();
                // Prints usage
                formatter.printHelp("java " + PAAgentServiceRMStarter.class.getName(), options);
            }
        }

        final PAAgentServiceRMStarter starter = new PAAgentServiceRMStarter();
        ResourceManager rm = starter.registerInRM(credentials, rmURL, nodeName, nodeSourceName);
        if (rm != null) {
            System.out.println("Connected to the Resource Manager at " + rmURL + "\n");
            // start pinging...
            // ping the rm to see if we are still connected
            // if not connected just exit
            // isActive throws an exception is not connected
            try {
                while (rm.nodeIsAvailable(starter.getNodeURL()).getBooleanValue()) {
                    try {
                        Thread.sleep(PING_DELAY_IN_MS);
                    } catch (InterruptedException e) {
                    }
                } // while connected
            } catch (Throwable e) {
                // no more connected to the RM
                System.out.println(
                        "The connection to the Resource Manager has been lost. The application will exit.");
                System.exit(1);
            }

            // if we are here it means we lost the connection. just exit..
            System.out.println("The Resource Manager has been shutdown. The application will exit. ");
            System.exit(2);
        } else {
            // Force system exit to bypass daemon threads
            System.exit(3);
        }
    }

    /**
     * Creates a local node, tries to join to the Resource Manager with a specified timeout
     * at the given URL, logs with provided credentials and adds the local node to
     * the Resource Manager. Handles all errors/exceptions.
     */
    private ResourceManager registerInRM(final Credentials credentials, final String rmURL, final String nodeName,
            final String nodeSourceName) {

        // 0 - read and set the rank
        String rankAsString = System.getProperty(RANK_PROP_NAME);
        if (rankAsString == null) {
            System.out.println("[WARNING] Rank is not set. Previous URLs will not be stored");
            this.removePrevious = false;
        } else {
            try {
                this.rank = Integer.parseInt(rankAsString);
                this.removePrevious = true;
                System.out.println("Rank is " + this.rank);
            } catch (Throwable e) {
                System.out.println("[WARNING] Rank cannot be read due to " + e.getMessage()
                        + ". Previous URLs will not be stored");
                this.removePrevious = false;
            }
        }

        // 1 - Create the local node that will be registered in RM
        Node localNode = null;
        try {
            localNode = NodeFactory.createLocalNode(nodeName, false, null, null);
            if (localNode == null) {
                throw new RuntimeException("The node returned by the NodeFactory is null");
            }
            this.nodeURL = localNode.getNodeInformation().getURL();
        } catch (Throwable t) {
            System.out.println("Unable to create the local node " + nodeName);
            t.printStackTrace();
            return null;
        }

        // Create the full url to contact the Resource Manager
        final String fullUrl = rmURL.endsWith("/") ? rmURL + RMConstants.NAME_ACTIVE_OBJECT_RMAUTHENTICATION
                : rmURL + "/" + RMConstants.NAME_ACTIVE_OBJECT_RMAUTHENTICATION;
        // 2 - Try to join the Resource Manager with a specified timeout
        RMAuthentication auth = null;
        try {
            auth = RMConnection.waitAndJoin(fullUrl, WAIT_ON_JOIN_TIMEOUT_IN_MS);
            if (auth == null) {
                throw new RuntimeException("The RMAuthentication instance is null");
            }
        } catch (Throwable t) {
            System.out.println("Unable to join the Resource Manager at " + rmURL);
            t.printStackTrace();
            return null;
        }

        ResourceManager rm = null;
        // 3 - Log using credential        
        try {
            rm = auth.login(credentials);
            if (rm == null) {
                throw new RuntimeException("The ResourceManager instance is null");
            }
        } catch (Throwable t) {
            System.out.println("Unable to log into the Resource Manager at " + rmURL);
            t.printStackTrace();
            return null;
        }

        // 4 - Add the created node to the Resource Manager with a specified 
        // number of attempts and a timeout between each attempt            
        boolean isNodeAdded = false;
        int attempts = 0;

        while ((!isNodeAdded) && (attempts < NB_OF_ADD_NODE_ATTEMPTS)) {
            attempts++;
            try {
                if (nodeSourceName == null) {
                    isNodeAdded = rm.addNode(this.nodeURL).getBooleanValue();
                } else {
                    isNodeAdded = rm.addNode(this.nodeURL, nodeSourceName).getBooleanValue();
                }
            } catch (AddingNodesException ex) {
                System.out.println("Unable to add the local node to the Resource Manager at " + rmURL);
                ex.printStackTrace();
                isNodeAdded = false;
            } catch (SecurityException ex) {
                System.out.println("Unable to add the local node to the Resource Manager at " + rmURL);
                ex.printStackTrace();
                isNodeAdded = false;
            }

            if (isNodeAdded) {
                if (removePrevious) {
                    // try to remove previous URL if different...
                    String previousURL = this.getAndDeleteNodeURL(nodeName, rank);
                    if (previousURL != null && !previousURL.equals(this.nodeURL)) {
                        System.out.println(
                                "Different previous URL registered by this agent has been found. Remove previous registration.");
                        rm.removeNode(previousURL, true);
                    }
                    // store the node URL
                    this.storeNodeURL(nodeName, rank, this.nodeURL);
                    System.out.println("Node " + this.nodeURL + " added. URL is stored in "
                            + getNodeURLFilename(nodeName, rank));
                } else {
                    System.out.println("Node " + this.nodeURL + " added.");
                }
            } else { // not yet registered
                System.out.println("Attempt number " + attempts + " out of " + NB_OF_ADD_NODE_ATTEMPTS
                        + " to add the local node to the Resource Manager at " + rmURL + " has failed.");
                try {
                    Thread.sleep(ADD_NODE_ATTEMPTS_DELAY_IN_MS);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        } // while

        if (!isNodeAdded) {
            System.out.println("The Resource Manager was unable to add the local node " + this.nodeURL + " after "
                    + NB_OF_ADD_NODE_ATTEMPTS + " attempts. The application will exit.");
            return null;
        } // if not registered

        return rm;
    }

    /**
     * Store in a temp file the current URL of the node started by the agent
     * @param nodeName the name of the node
     * @param rank the rank of the node
     * @param nodeURL the URL of the node
     */
    private void storeNodeURL(String nodeName, int rank, String nodeURL) {
        try {
            File f = new File(getNodeURLFilename(nodeName, rank));
            if (f.exists()) {
                System.out.println("[WARNING] NodeURL file already exists ; delete it.");
                f.delete();
            }
            BufferedWriter out = new BufferedWriter(new FileWriter(f));
            out.write(nodeURL);
            out.write(System.getProperty("line.separator"));
            out.close();
        } catch (IOException e) {
            System.out.println("[WARNING] NodeURL cannot be created.");
            e.printStackTrace();
        }
    }

    /**
     * Return the previous URL of this node
     * @param nodeName the name of the node started by the Agent
     * @param rank the rank of the node
     * @return the previous URL of this node, null if none can be found
     */
    private String getAndDeleteNodeURL(String nodeName, int rank) {
        try {
            File f = new File(getNodeURLFilename(nodeName, rank));
            if (f.exists()) {
                BufferedReader in = new BufferedReader(new FileReader(f));
                String read = in.readLine();
                in.close();
                f.delete();
                return read;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * Create the name of the temp file for storing node URL.
     */
    private String getNodeURLFilename(String nodeName, int rank) {
        final String tmpDir = System.getProperty("java.io.tmpdir");
        final String tmpFile = new File(tmpDir, URL_TMPFILE_PREFIX + "_" + nodeName + "-" + rank).getAbsolutePath();
        return tmpFile;
    }

}