org.lsc.jmx.LscAgent.java Source code

Java tutorial

Introduction

Here is the source code for org.lsc.jmx.LscAgent.java

Source

/*
 ****************************************************************************
 * Ldap Synchronization Connector provides tools to synchronize
 * electronic identities from a list of data sources including
 * any database with a JDBC connector, another LDAP directory,
 * flat files...
 *
 *                  ==LICENSE NOTICE==
 * 
 * Copyright (c) 2008 - 2011 LSC Project 
 * 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 LSC Project 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 HOLDERS 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 COPYRIGHT OWNER
 * 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.
 *
 *                  ==LICENSE NOTICE==
 *
 *               (c) 2008 - 2011 LSC Project
 *         Sebastien Bahloul <seb@lsc-project.org>
 *         Thomas Chemineau <thomas@lsc-project.org>
 *         Jonathan Clarke <jon@lsc-project.org>
 *         Remy-Christophe Schermesser <rcs@lsc-project.org>
 ****************************************************************************
 */
package org.lsc.jmx;

import java.io.IOException;
import java.net.MalformedURLException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.StringTokenizer;

import javax.management.JMX;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.Notification;
import javax.management.NotificationListener;
import javax.management.ObjectName;
import javax.management.remote.JMXServiceURL;
import javax.management.remote.rmi.RMIConnector;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.lang.ArrayUtils;
import org.lsc.beans.SimpleBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * JMX Agent - Provide the ability to start/stop/get status of asynchronous
 * tasks
 * 
 * By default this agent is only used on local call
 * 
 * @author Sebastien Bahloul &lt;seb@lsc-project.org&gt;
 */
public class LscAgent implements NotificationListener {

    /** The local logger */
    private static final Logger LOGGER = LoggerFactory.getLogger(LscAgent.class);

    /** When asking for an operation, this field contains the task */
    private String taskName;

    /** The different asynchronous task operation types */
    public enum OperationType {
        START, STOP, STATUS, TASKS_LIST, UNKNOWN,
    }

    /** The operation type */
    private OperationType operation;

    /** Specify the URL */
    private JMXServiceURL url;
    /** The RMI connector */
    private RMIConnector jmxC;
    /** The MBean server connection */
    private MBeanServerConnection jmxc;
    /** The LSC Server MBean */
    private LscServer lscServer;
    /** The IP hostname */
    private String hostname;
    /** The TCP port */
    private String port;
    /** Identifier to synchronize */
    private String idToSync;
    /** Identifier to synchronize */
    private Map<String, String> attrsToSync;

    /**
     * Default constructor
     */
    public LscAgent() {
        operation = OperationType.UNKNOWN;
        attrsToSync = new HashMap<String, String>();
    }

    public static void main(String[] args) {
        LscAgent jmxAgent = new LscAgent();
        int retCode = jmxAgent.parseOptions(args);
        if (retCode > 0) {
            System.exit(retCode);
        }
        System.exit(jmxAgent.run(jmxAgent.getOperation()));
    }

    public int run(OperationType operation) {
        if (!jmxBind()) {
            System.exit(1);
            return 1;
        }
        switch (operation) {
        case START:
            if (idToSync != null) {
                if (lscServer.launchSyncTaskById(taskName, idToSync, attrsToSync)) {
                    LOGGER.info("Synchronization per id successfully achieved.");
                } else {
                    LOGGER.error("Synchronization per id failed !");
                    return 2;
                }
            } else {
                lscServer.startAsyncTask(taskName);
            }
            break;
        case STOP:
            lscServer.shutdownAsyncTask(taskName);
            break;
        case STATUS:
            boolean status = lscServer.isAsyncTaskRunning(taskName);
            if (ArrayUtils.contains(lscServer.getAsyncTasksName(), taskName)) {
                LOGGER.info("Asynchronous task " + taskName + " is " + (status ? "running" : "stopped"));
            } else if (ArrayUtils.contains(lscServer.getSyncTasksName(), taskName)) {
                LOGGER.info("Synchronous task " + taskName + " is " + (status ? "running" : "stopped"));
            } else {
                LOGGER.error("Unknown or synchronous task name: " + taskName);
                return 3;
            }

            // Display full taks status
            if (status) {
                String fullStatus = lscServer.getTaskStatus(taskName);
                LOGGER.info(fullStatus);
                return 0;
            }

            return 1;
        case TASKS_LIST:
            LOGGER.info("Available asynchronous tasks are: ");
            for (String taskName : lscServer.getAsyncTasksName()) {
                LOGGER.info(" - " + taskName);
            }
            LOGGER.info("Available synchronous tasks are: ");
            for (String taskName : lscServer.getSyncTasksName()) {
                LOGGER.info(" - " + taskName);
            }
            break;
        default:

        }
        jmxUnbind();
        return 0;
    }

    public boolean syncByObject(String taskName, String id, Map<String, List<String>> map) {
        if (!jmxBind()) {
            return false;
        }
        SimpleBean bean = new SimpleBean();
        bean.setMainIdentifier(id);
        for (Entry<String, List<String>> entry : map.entrySet()) {
            bean.setDataset(entry.getKey(), new HashSet<Object>(Arrays.asList(entry.getValue().toArray())));
        }
        return lscServer.launchSyncTask(taskName, bean);
    }

    /**
     * Manage command line options.
     * 
     * @param args command line
     * @return the status code (0: OK, >=1 : failed)
     */
    protected int parseOptions(final String[] args) {
        Options options = new Options();
        options.addOption("a", "start", true, "Start an asynchronous task");
        options.addOption("h", "hostname", true, "Specify the hostname to connect to");
        options.addOption("l", "list", false, "List the available asynchronous tasks");
        options.addOption("o", "stop", true, "Stop an asynchronous task");
        options.addOption("p", "port", true, "Specify the port to connect to");
        options.addOption("i", "identifier", true, "Specify the identifier to synchronize");
        options.addOption("t", "attributes", true,
                "Specify the attributes pivot to synchronize (comma separated, identifier parameter required)");
        options.addOption("s", "status", true, "Get a task status");

        CommandLineParser parser = new GnuParser();

        try {
            CommandLine cmdLine = parser.parse(options, args);
            if (cmdLine.hasOption("a")) {
                operation = OperationType.START;
                taskName = cmdLine.getOptionValue("a");
            }
            if (cmdLine.hasOption("l")) {
                operation = OperationType.TASKS_LIST;
            }
            if (cmdLine.hasOption("o")) {
                operation = OperationType.STOP;
                taskName = cmdLine.getOptionValue("o");
            }
            if (cmdLine.hasOption("s")) {
                operation = OperationType.STATUS;
                taskName = cmdLine.getOptionValue("s");
            }
            if (cmdLine.hasOption("i")) {
                idToSync = cmdLine.getOptionValue("i");
                if (cmdLine.hasOption("t")) {
                    StringTokenizer attrsStr = new StringTokenizer(cmdLine.getOptionValue("t"), ",");
                    while (attrsStr.hasMoreTokens()) {
                        String token = attrsStr.nextToken();
                        if (token.contains("=")) {
                            attrsToSync.put(token.substring(0, token.indexOf("=")),
                                    token.substring(token.indexOf("=") + 1));
                        } else {
                            LOGGER.error(
                                    "Unknown attribute name=value couple in \"{}\". Please check your parameters !",
                                    token);
                            printHelp(options);
                            return 1;
                        }
                    }
                }
            } else if (cmdLine.hasOption("t")) {
                LOGGER.error("Attributes specified, but missing identifier !");
                printHelp(options);
                return 1;
            }
            if (cmdLine.hasOption("h")) {
                hostname = cmdLine.getOptionValue("h");
            } else {
                hostname = "localhost";
                LOGGER.info("Hostname parameter not specified, using {} as default value.", hostname);
            }
            if (cmdLine.hasOption("p")) {
                port = cmdLine.getOptionValue("p");
            } else {
                port = "1099";
                LOGGER.info("TCP Port parameter not specified, using {} as default value.", port);
            }
            if (operation == OperationType.UNKNOWN) {
                printHelp(options);
                return 1;
            }
        } catch (ParseException e) {
            LOGGER.error("Unable to parse the options ({})", e.toString());
            LOGGER.debug(e.toString(), e);
            return 1;
        }
        return 0;
    }

    /**
     * Print the command line help.
     * 
     * @param options
     *            specified options to manage
     */
    private static void printHelp(final Options options) {
        HelpFormatter formatter = new HelpFormatter();
        formatter.printHelp("lsc", options);
    }

    /**
     * Bind to the JMX Server 
     */
    public boolean jmxBind() {
        try {
            String sUrl = "service:jmx:rmi:///jndi/rmi://" + hostname + ":" + port + "/jmxrmi";
            LOGGER.info("Connecting to remote engine on : " + sUrl);
            url = new JMXServiceURL(sUrl);
            jmxC = new RMIConnector(url, null);
            jmxC.connect();
            jmxc = jmxC.getMBeanServerConnection();
            ObjectName lscServerName = new ObjectName("org.lsc.jmx:type=LscServer");
            lscServer = JMX.newMXBeanProxy(jmxc, lscServerName, LscServer.class, true);
            return true;
        } catch (MalformedObjectNameException e) {
            LOGGER.error(e.toString(), e);
        } catch (NullPointerException e) {
            LOGGER.error(e.toString(), e);
        } catch (MalformedURLException e) {
            LOGGER.error(e.toString(), e);
        } catch (IOException e) {
            LOGGER.error(e.toString(), e);
        }
        return false;
    }

    /**
     * Unbind from the JMX Server 
     */
    protected boolean jmxUnbind() {
        try {
            jmxC.close();
            return true;
        } catch (IOException e) {
            LOGGER.error(e.toString(), e);
        }
        return false;
    }

    public void handleNotification(Notification notification, Object handback) {
        LOGGER.info("\nReceived notification: " + notification);
    }

    public OperationType getOperation() {
        return operation;
    }
}