/*
 * JBoss, Home of Professional Open Source
 * Copyright 2005, JBoss Inc., and individual contributors as indicated
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.jboss.mx.remoting;

import java.util.StringTokenizer;

import javax.management.MBeanServer;

import org.jboss.remoting.InvokerLocator;
import org.jboss.remoting.ConnectionFailedException;
import org.jboss.remoting.ident.Identity;
import org.jboss.logging.Logger;

/**
 * MBeanTransportPreference is a utility class that will take into account the VM's setup transport
 * preferences when trying to create a preferred connection back to a remote MBeanServer.  Since there
 * are cases when multiple invoker transports can exist and all be valid, this will help determine which
 * order the transports should be attempted.  You wouldn't want to connect via SOAP, in most cases, when
 * TCP/IP via Sockets is available.  There are cases however you do want to explicitly choose SOAP vs.
 * Sockets or RMI, and in which case your preference order might be <tt>soap, socket, rmi.</tt>
 *
 * @author <a href="mailto:jhaynie@vocalocity.net">Jeff Haynie</a>
 * @version $Revision: 1.1.2.2 $
 */
public class MBeanTransportPreference
{
    private static final transient Logger log = Logger.getLogger(MBeanTransportPreference.class.getName());

    // NOTE: we need to maybe think this through on how this really should work long term..
    private static String _preferences = System.getProperty("jboss.transport.preferences","socket,rmi,soap");
    private static String preferences[] = initialize(_preferences);
    private static MBeanServer ourServer;
    private static Identity ourIdentity;

    public static void setLocalServer (MBeanServer server, Identity identity)
    {
        if (log.isDebugEnabled())
        {
            log.debug("setLocalServer called - server="+server+",identity="+identity);
        }
        ourServer = server;
        ourIdentity = identity;
    }

    private static String[] initialize (String list)
    {
        if (list==null)
        {
            return new String[1];
        }
        StringTokenizer tok=new StringTokenizer(list,",");
        String pref [] = new String[tok.countTokens()];
        int c=0;
        while(tok.hasMoreTokens())
        {
            String token=tok.nextToken();
            pref[c++]=token.trim();
        }
        return pref;
    }
    /**
     * set the order to use when selecting transports to connect to a remote server
     *
     * @param order
     */
    public static void setTransportPreferences (String order[])
    {
        preferences = (order==null || order.length<=0) ? initialize(_preferences) : order;
    }
    /**
     * get the order to use when selecting transports to connect to a remote server
     *
     * @return
     */
    public static String[] getTransportPreferences ()
    {
        return preferences;
    }
    /**
     * return a server transport to a MBeanServer on a remote server, using the transport
     * preference order specified by the user
     *
     * @param identity
     * @param locators
     * @return
     * @throws ConnectionFailedException
     */
    public static MBeanServer getServerByTransport (Identity identity, InvokerLocator locators[])
        throws ConnectionFailedException
    {
        if (log.isDebugEnabled())
        {
            log.debug("getServerByTransport for identity="+identity+", ours is="+ourIdentity);
        }
        if (ourIdentity==null)
        {
            if (ourServer==null)
            {
                 ourServer = JMXUtil.getMBeanServer();
            }
            ourIdentity = Identity.get(ourServer);
        }
        if (identity.isSameJVM(ourIdentity))
        {
            return ourServer;
        }
        for (int c=0;c<preferences.length;c++)
        {
            String transport = preferences[c];

            if (transport!=null)
            {
                for (int x=0;x<locators.length;x++)
                {
                    if (locators[x].getProtocol().equals(transport))
                    {
                        // attempt connect to this first one in our pref list
                        try
                        {
                            MBeanServer svr = MBeanServerRegistry.getMBeanServerFor(locators[x]);
                            if (svr!=null)
                            {
                                return svr;
                            }
                            svr = MBeanServerClientInvokerProxy.create(locators[x],ourIdentity.getJMXId(),identity.getJMXId());
                            if (svr!=null)
                            {
                                return svr;
                            }
                        }
                        catch (Throwable ex) {}
                    }
                }
            }
        }
        for (int x=0;x<locators.length;x++)
        {
            // attempt connect to this first one in our pref list
            try
            {
				if (log.isDebugEnabled())
				{
				   log.debug("attempting to connect via locator["+x+"] ("+locators[x]+") to: "+identity);
			    }
                MBeanServer svr = MBeanServerRegistry.getMBeanServerFor(locators[x]);
                if (svr!=null)
                {
                    return svr;
                }
                svr = MBeanServerClientInvokerProxy.create(locators[x],ourIdentity.getJMXId(),identity.getJMXId());
                if (svr!=null)
                {
                    return svr;
                }
            }
            catch (Throwable ex)
            {
				if (log.isDebugEnabled())
				{
					log.debug("Error connecting ... ",ex);
				}
			}
        }
        throw new ConnectionFailedException ("No transport/connection available to connect to: "+identity);
    }
}
