/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2000-2010 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.messaging.bridge;

import java.util.Properties;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Map;
import java.util.HashMap;
import java.util.Locale;
import javax.jms.*;
import com.sun.messaging.bridge.service.Bridge;
import com.sun.messaging.bridge.service.BridgeContext;
import com.sun.messaging.bridge.service.FaultInjection;
import com.sun.messaging.bridge.service.BridgeException;
import com.sun.messaging.bridge.resources.BridgeManagerResources;
import com.sun.messaging.bridge.admin.handlers.AdminMessageHandler;
import com.sun.messaging.bridge.admin.util.AdminMessageType;
import com.sun.messaging.jmq.io.Status;
import com.sun.messaging.bridge.resources.BridgeManagerResources;
import com.sun.messaging.bridge.service.BridgeCmdSharedResources;
import com.sun.messaging.bridge.service.BridgeCmdSharedReplyData;
import com.sun.messaging.bridge.service.JMSBridgeStore;
import com.sun.messaging.bridge.service.DupKeyException;

/**
 * The Bridge Services Manager
 *
 * @author amyk
 */
public class BridgeServiceManagerImpl extends BridgeServiceManager
                     implements ExceptionListener, MessageListener 
{

    private enum State {UNINITIALIZED, STOPPING, STOPPED, STARTING, STARTED};
    private static boolean DEBUG = false;

    private static BridgeManagerResources _bmr = getBridgeManagerResources();
    private static Map<Locale, BridgeManagerResources> _bmrs = Collections.synchronizedMap(
                                              new HashMap<Locale, BridgeManagerResources>());

    private Map<String, Bridge> _bridges = Collections.synchronizedMap(
                                   new LinkedHashMap<String, Bridge>()); 
    private BridgeBaseContext _bc = null;

    private com.sun.messaging.ConnectionFactory _cf = null;
    private Connection _connection = null;
    private Session _session = null;
    private String _user = null;
    private String _passwd = null;
    private TemporaryQueue _adminQueue = null; 

    private State _state = State.UNINITIALIZED;

    private AdminMessageHandler _adminHandler = null;

    /**
     *  
     */
    public BridgeServiceManagerImpl() {} 

    /**
     * Initialize the bridge service manager 
     */
    public synchronized void init(BridgeBaseContext ctx) throws Exception {
        com.sun.messaging.jmq.jmsclient.Debug.setUseLogger(true);
        FaultInjection.setBridgeBaseContext(ctx);

        _bc = ctx;
        Properties props = _bc.getBridgeConfig();

        String activekey = props.getProperty(BridgeBaseContext.PROP_PREFIX)+".activelist";
        List<String> alist = BridgeUtil.getListProperty(activekey, props);
        int size = alist.size();

        String name = null;
        Iterator<String> itr = alist.iterator();
        while (itr.hasNext()) {
            name = itr.next();
            try {
                loadBridge(name);
            } catch (BridgeException e) {
                if (e.getStatus() == Status.NOT_MODIFIED) continue;

                _bc.logError(_bmr.getKString(_bmr.E_LOAD_BRIDGE_FAILED, name, e.getMessage()),  null);
                throw e;
            }
        }

        if (_bc.isHAEnabled()) {
            
            JMSBridgeStore store = (JMSBridgeStore)_bc.getJDBCStore();
            if (store == null) throw new BridgeException("null JDBC store");

            List jmsbridges = store.getJMSBridges(null);

            name = null;
            itr = alist.iterator();
            while (itr.hasNext()) {
                name = itr.next();
                String type = props.getProperty(
                              props.getProperty(
                              BridgeBaseContext.PROP_PREFIX)+"."+name+".type");
                if (type == null) {
                    throw new BridgeException(_bmr.getString(_bmr.X_BRIDGE_NO_TYPE, name));
                }
                if (!type.trim().toUpperCase().equals(Bridge.JMS_TYPE)) {
                    continue;
                }
                if (jmsbridges.contains(name)) {
                    continue;
                }
                try {
                    store.addJMSBridge(name, true, null);
                } catch (DupKeyException e)  {
                    _bc.logInfo(_bmr.getKString(_bmr.I_JMSBRIDGE_NOT_OWNER, name), null);
                    itr.remove();
                }
            }
            jmsbridges = store.getJMSBridges(null);
            itr = jmsbridges.iterator();
            while (itr.hasNext()) {
                name = itr.next();
                if (alist.contains(name)) {
                    continue;
                }
                alist.add(name);
                try {
                    loadBridge(name);
                } catch (BridgeException e) {
                    _bc.logError(_bmr.getKString(_bmr.E_LOAD_BRIDGE_FAILED, name, e.getMessage()),  null);
                    throw e;
                }
            }
            if (alist.size() != size) {
                StringBuffer sb = new StringBuffer();
                int i = 0;
                itr = alist.iterator();
                while (itr.hasNext()) {
                    if (i > 0) sb.append(",");
                    sb.append(itr.next());
                    i++;
                }
                Properties p = new Properties();
                p.setProperty(activekey, sb.toString());
                _bc.updateBridgeConfig(p);
            }
        }


        String keyu = props.getProperty(BridgeBaseContext.PROP_PREFIX)+ctx.PROP_ADMIN_USER_SUFFIX;
        String keyp = props.getProperty(BridgeBaseContext.PROP_PREFIX)+ctx.PROP_ADMIN_PASSWORD_SUFFIX;
        _user = props.getProperty(keyu);
        _passwd = props.getProperty(keyp); 
        if (_user == null || _user.trim().length() == 0) {
            throw new JMSException(_bmr.getString(_bmr.X_BRIDGE_NO_ADMIN_USER, keyu));
        }
        _user = _user.trim();
        if (_passwd  == null || _passwd.trim().length() == 0) {
            throw new JMSException(_bmr.getString(_bmr.X_BRIDGE_NO_ADMIN_PASSWORD, keyp));
        } 
        _passwd = _passwd.trim();

        _adminHandler = new AdminMessageHandler(this);

        _state = State.STOPPED;
    }

    public synchronized boolean isRunning() {
        return (_state == State.STARTED);
    }

    public synchronized String getAdminDestinationName() throws Exception {
        if (_state != State.STARTED) {
            throw new BridgeException(_bmr.getString(_bmr.X_BRIDGE_SERVICE_MANAGER_NOT_RUNNING));
        }
        return _adminQueue.getQueueName();
    }

    public String getAdminDestinationClassName() throws Exception {
        if (_state != State.STARTED) {
            throw new BridgeException(_bmr.getString(_bmr.X_BRIDGE_SERVICE_MANAGER_NOT_RUNNING));
        }
        return _adminQueue.getClass().getName();
    }

    /**
     * Start the bridge service manager
     */
    public synchronized void start() throws Exception {
        if (_bc == null || _state == State.UNINITIALIZED) {
            throw new BridgeException(_bmr.getString(_bmr.X_BRIDGE_SERVICE_MANAGER_NOT_INITED));
        }
        _state = State.STARTING;

        Properties props = _bc.getBridgeConfig();

        try {

        Bridge b = null;
        String name = null;
        for (Map.Entry<String, Bridge> pair: _bridges.entrySet()) {
            b = pair.getValue();
            name = b.getName();
            String autostart = props.getProperty(
                               props.getProperty(
                               BridgeBaseContext.PROP_PREFIX)+"."+name+".autostart", "true");
            boolean doautostart = Boolean.valueOf(autostart);
            try {
                if (doautostart) {
                    String[] args = null;
                    if (_bc.isStartWithReset()) args = new String[]{"-reset"};
                    startBridge(b, args);
                }
            } catch (BridgeException e) {
                if (e.getStatus() == Status.CREATED) {
                    continue; 
                }
                throw e;
            }
        }

        } catch (Exception e) {
            try {
                stopBridge(null, null, null);
            } catch (Throwable t) { }
            throw e;
        }

        try {
        _cf = new com.sun.messaging.ConnectionFactory();
        _cf.setProperty(com.sun.messaging.ConnectionConfiguration.imqAddressList,
                        _bc.getBrokerServiceAddress("tcp",
                            com.sun.messaging.jmq.ClientConstants.CONNECTIONTYPE_ADMIN));

        _cf.setProperty(com.sun.messaging.ConnectionConfiguration.imqReconnectEnabled, "false");

        _connection = _cf.createConnection(_user, _passwd);
        _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
		_adminQueue = _session.createTemporaryQueue();
        MessageConsumer mc = _session.createConsumer(_adminQueue);
        mc.setMessageListener(this);
        _connection.start();

        } catch (Exception e) {
            try {
                stopBridge(null, null, null);
                if (_connection != null) _connection.close();
            } catch (Throwable t) { }
            
            throw e;
        }
        _state = State.STARTED;
    }

    /**
     *
     */
    public synchronized void loadBridge(String name) throws Exception {
        _bc.logInfo("Loading bridge "+name, null);

        Bridge b = _bridges.get(name);
        if (b != null) { 
            _bc.logInfo("Bridge "+name+" is already loaded.", null);
           throw new BridgeException(_bmr.getString(_bmr.I_BRIDGE_ALREADY_LOADED, name), Status.NOT_MODIFIED);
        }

        Properties props = _bc.getBridgeConfig();

        /*
        String activekey = props.getProperty(
                                  BridgeBaseContext.PROP_PREFIX)+".activelist";
        List<String> alist = BridgeUtil.getListProperty(activekey, props);
        
        String tmpn = null;
        boolean found = false;
        Iterator<String> itr = alist.iterator();
        while (itr.hasNext()) {
            tmpn = itr.next();
            if (tmpn.equals(name)) {
                found = true;
                break; 
            }
        }
        if (!found) {
            String oldactives = props.getProperty(activekey);
            String newactives = oldactives+","+name;
            Properties p = new Properties();
            p.setProperty(activekey, newactives);
            _bc.updateBridgeConfig(p);
        }
        */

        props = _bc.getBridgeConfig();
        String type = props.getProperty(
                      props.getProperty(
                      BridgeBaseContext.PROP_PREFIX)+"."+name+".type");
        if (type == null) {
            String emsg = _bmr.getKString(_bmr.E_LOAD_BRIDGE_NO_TYPE, name);
            _bc.logError(emsg, null);
            throw new BridgeException(emsg);
        }
        type = type.toLowerCase();

        String classn = props.getProperty(
                        props.getProperty(
                        BridgeBaseContext.PROP_PREFIX)+"."+type+".class");

        if (classn == null) {
            String emsg = _bmr.getKString(_bmr.E_LOAD_BRIDGE_NO_CLASS, name);
            _bc.logError(emsg, null);
            throw new BridgeException(emsg);
        }


        b = (Bridge)Class.forName(classn).newInstance();

        if (!b.isMultipliable() && !b.getType().toLowerCase().equals(name.toLowerCase())) {
            String emsg =  _bmr.getKString(_bmr.E_BRIDGE_NAME_TYPE_NOT_SAME, name, b.getType());
            _bc.logError(emsg, null);
            throw new BridgeException(emsg);
        }

        if (DEBUG) {
            _bc.logInfo("Loaded brigde "+name+" by classloader "+
                        b.getClass().getClassLoader()+ 
                        "(parent:"+this.getClass().getClassLoader()+")", null);
        }

        b.setName(name);
        _bridges.put(name, b);

        _bc.logInfo("Loaded bridge "+name, null);

    }

    /**
     *
     * @return true if started successful, false if asynchronously started
     *
     * @throws Exception if start failed
     */
    public synchronized boolean startBridge(String name, String[] args, String type) throws Exception {

        if (type != null && 
            !type.equals(Bridge.JMS_TYPE) && !type.equals(Bridge.STOMP_TYPE)) { 
            throw new IllegalArgumentException(_bmr.getKString(_bmr.X_BRIDGE_INVALID_TYPE, type));
        }
        Bridge b = null;
        if (name != null) {
            b = _bridges.get(name);
            if (b == null) { 
                throw new BridgeException(_bmr.getKString(_bmr.X_BRIDGE_NAME_NOT_FOUND, name));
            }
            if (type != null && !type.equals(b.getType())) {
                String[] eparam = new String[] {name, b.getType(), type};
                throw new  BridgeException(_bmr.getKString(_bmr.X_BRIDGE_TYPE_MISMATCH, eparam));
            }
            return startBridge(b, args);
        }

        boolean async = false;
        for (Map.Entry<String, Bridge> pair: _bridges.entrySet()) {
            b = pair.getValue();
            if (type != null && !b.getType().equals(type)) continue;

            if (!startBridge(b, args)) {
                async = true;
            }
        }
        return !async;
    }

    /**
     * @param name must not be null
     *
     * @return true if started successful, false if asynchronously started
     *
     * @throws Exception if start failed
     */
    private boolean startBridge(Bridge b, String[] args) throws Exception {
         if (args == null) {
             _bc.logInfo(_bmr.getString(_bmr.I_STARTING_BRIDGE, b.getName()), null);
         }

         if (b.getState() == Bridge.State.STARTED && args == null) {
             _bc.logInfo(_bmr.getString(_bmr.I_BRIDGE_ALREADY_STARTED, b.getName()), null);
             return true;
         } 

         BridgeContext ctx = new BridgeContext(_bc, b.getName());
         StringBuffer sf = new StringBuffer();
         sf.append(_bmr.getString(_bmr.I_STARTING_BRIDGE_WITH_PROPS, b.getName()));
         String key = null;
         Enumeration e = ctx.getConfig().propertyNames();
         while (e.hasMoreElements()) {
             key = (String)e.nextElement();
             sf.append("\t"+key+"="+ctx.getConfig().getProperty(key)+"\n");
         }
         if (args == null) {
             _bc.logInfo(sf.toString(), null);
         }

         try {
             boolean ret = b.start(ctx, args);
             if (args == null) {
                 _bc.logInfo(_bmr.getString(_bmr.I_STARTED_BRIDGE, b.getName()), null);
             }
             return ret;
         } catch (Exception e1) {
             _bc.logError(_bmr.getKString(_bmr.E_START_BRIDGE_FAILED, b.getName(), e1.getMessage()), null);
             throw e1;
         }
    }

    /**
     *
     */
    public synchronized void stopBridge(String name, String[] args, String type) throws Exception {

        if (type != null &&
            !type.equals(Bridge.JMS_TYPE) && !type.equals(Bridge.STOMP_TYPE)) {
            throw new IllegalArgumentException(_bmr.getKString(_bmr.X_BRIDGE_INVALID_TYPE, type));
        }
        Bridge b = null;
        if (name != null) {
            b = _bridges.get(name);
            if (b == null) {
                throw new BridgeException(_bmr.getKString(_bmr.X_BRIDGE_NAME_NOT_FOUND, name));
            }
            if (type != null && !type.equals(b.getType())) {
                String[] eparam = new String[] {name, b.getType(), type};
                throw new BridgeException(_bmr.getKString(_bmr.X_BRIDGE_TYPE_MISMATCH, eparam));
            }
            stopBridge(b, args);
            return;
        }

        for (Map.Entry<String, Bridge> pair: _bridges.entrySet()) {
             b = pair.getValue();
             if (type != null && !b.getType().equals(type)) continue;

             stopBridge(b, args);
        }
    }


    /**
     *
     */
    public synchronized void pauseBridge(String name, String[] args, String type) throws Exception {

        if (type != null &&
            !type.equals(Bridge.JMS_TYPE) && !type.equals(Bridge.STOMP_TYPE)) {
            throw new IllegalArgumentException(_bmr.getKString(_bmr.X_BRIDGE_INVALID_TYPE, type));
        }
        if (name == null && type == null) {
            throw new UnsupportedOperationException(_bmr.getKString(_bmr.X_BRIDGE_PAUSE_NO_TYPE));
        }
        Bridge b = null;
        if (name != null) {
            b = _bridges.get(name);
            if (b == null) {
                throw new BridgeException(_bmr.getKString(_bmr.X_BRIDGE_NAME_NOT_FOUND, name));
            }
            if (type != null && !type.equals(b.getType())) {
                String[] eparam = new String[] {name, b.getType(), type};
                throw new BridgeException(_bmr.getKString(_bmr.X_BRIDGE_TYPE_MISMATCH, eparam));
            }
            pauseBridge(b, args);
            return;
        }

        for (Map.Entry<String, Bridge> pair: _bridges.entrySet()) {
             b = pair.getValue();
             if (type != null && !b.getType().equals(type)) continue;

             pauseBridge(b, args);
        }
    }


    /**
     *
     */
    public synchronized void resumeBridge(String name, String[] args, String type) throws Exception {

        if (type != null &&
            !type.equals(Bridge.JMS_TYPE) && !type.equals(Bridge.STOMP_TYPE)) {
            throw new IllegalArgumentException(_bmr.getKString(_bmr.X_BRIDGE_INVALID_TYPE, type));
        }
        if (name == null && type == null) {
            throw new UnsupportedOperationException(_bmr.getKString(_bmr.X_BRIDGE_RESUME_NO_TYPE));
        }

        Bridge b = null;
        if (name != null) {
            b = _bridges.get(name);
            if (b == null) {
                throw new BridgeException(_bmr.getKString(_bmr.X_BRIDGE_NAME_NOT_FOUND, name));
            }
            if (type != null && !type.equals(b.getType())) {
                String[] eparam = new String[] {name, b.getType(), type};
                throw new BridgeException(_bmr.getKString(_bmr.X_BRIDGE_TYPE_MISMATCH, eparam));
            }
            resumeBridge(b, args);
            return;
        }

        for (Map.Entry<String, Bridge> pair: _bridges.entrySet()) {
             b = pair.getValue();
             if (type != null && !b.getType().equals(type)) continue;

             resumeBridge(b, args);
        }
    }

    /**
     *
     */
    public synchronized void pauseBridge(Bridge b, String[] args) throws Exception {
        _bc.logInfo(_bmr.getString(_bmr.I_PAUSING_BRIDGE, b.getName()), null);

        if (b.getState() == Bridge.State.PAUSED && args == null) {
             _bc.logInfo(_bmr.getString(_bmr.I_BRIDGE_ALREADY_PAUSED, b.getName()), null);
             return;
         }

        b.pause(new BridgeContext(_bc, b.getName()), args);
        _bc.logInfo(_bmr.getString(_bmr.I_PAUSED_BRIDGE, b.getName()), null);
    }

    /**
     *
     */
    public synchronized void resumeBridge(Bridge b, String[] args) throws Exception {
        _bc.logInfo(_bmr.getString(_bmr.I_RESUMING_BRIDGE, b.getName()), null);

        if (b.getState() == Bridge.State.STARTED && args == null) {
             _bc.logInfo(_bmr.getString(_bmr.I_BRIDGE_IS_RUNNING, b.getName()), null);
             return;
         }

        b.resume(new BridgeContext(_bc, b.getName()), args);
        _bc.logInfo(_bmr.getString(_bmr.I_RESUMED_BRIDGE, b.getName()), null);

    }

    /**
     *
     */
    public synchronized void unloadBridge(String name) throws Exception {
        _bc.logInfo("Unloading bridge "+name, null);

        Bridge b = _bridges.get(name);
        if (b == null) { 
            _bc.logInfo("Bridge "+name+" is not loaded.",  null);
            throw new BridgeException("Bridge "+name+" is not loaded.", Status.NOT_MODIFIED);
        }
        stopBridge(name, null, null);
        _bridges.remove(name);
        b.setName(null);

        Properties props = _bc.getBridgeConfig();
        List<String> alist = BridgeUtil.getListProperty(
                                props.getProperty(
                                BridgeBaseContext.PROP_PREFIX)+".activelist", props);
        
        String tmpn = null;
        StringBuffer sbuf = new StringBuffer();
        Iterator<String> itr = alist.iterator();
        while (itr.hasNext()) {
            tmpn = itr.next();
            if (!tmpn.equals(name)) {
                if (sbuf.length() > 0 ) {
                    sbuf.append(",");
                }
                sbuf.append(tmpn);
            }
        }
        Properties p = new Properties();
        p.setProperty(props.getProperty(BridgeBaseContext.PROP_PREFIX)+".activelist",
                      sbuf.toString());
        _bc.updateBridgeConfig(p);

        _bc.logInfo("Unloaded bridge "+name, null);
    }

    /**
     *
     */
    private void stopBridge(Bridge b, String[] args) throws Exception {

        if (b.getState() == Bridge.State.STOPPED && args == null) {
             _bc.logDebug(_bmr.getString(_bmr.I_BRIDGE_ALREADY_STOPPED, b.getName()), null);
             return;
         }

        _bc.logInfo(_bmr.getString(_bmr.I_STOPPING_BRIDGE, b.getName()), null);

        b.stop(new BridgeContext(_bc, b.getName()), args);
        _bc.logInfo(_bmr.getString(_bmr.I_STOPPED_BRIDGE, b.getName()), null);
    }

    /**
     */
    public synchronized ArrayList<BridgeCmdSharedReplyData> listBridge(
                               String name, String[] args, String type,
                               BridgeManagerResources bmr)
                               throws Exception {

        if (type != null && 
            !type.equals(Bridge.JMS_TYPE) && !type.equals(Bridge.STOMP_TYPE)) { 
            throw new IllegalArgumentException(_bmr.getString(_bmr.X_BRIDGE_INVALID_TYPE, type));
        }

        if (name == null) { 
            _bc.logDebug("Listing all bridges (type="+type+")" , null);

            BridgeCmdSharedReplyData reply = new BridgeCmdSharedReplyData(3, 4, "-");
            String   oneRow[] = new String [3]; 
            oneRow[0] =  bmr.getString(BridgeCmdSharedResources.I_BGMGR_TITLE_BRIDGE_NAME);
            oneRow[1] =  bmr.getString(BridgeCmdSharedResources.I_BGMGR_TITLE_BRIDGE_TYPE);
            oneRow[2] =  bmr.getString(BridgeCmdSharedResources.I_BGMGR_TITLE_BRIDGE_STATE);
            reply.addTitle(oneRow);

            Bridge b = null;
            for (Map.Entry<String, Bridge> pair: _bridges.entrySet()) {
                b = pair.getValue();
                if (type != null && !b.getType().equals(type)) continue;
                oneRow[0] = b.getName(); 
                oneRow[1] = b.getType();
                oneRow[2] = b.getState().toString(bmr); 
                reply.add(oneRow);
            }
            _bc.logDebug("Listed all bridges (type="+type+")", null);
            ArrayList<BridgeCmdSharedReplyData> replys = new ArrayList<BridgeCmdSharedReplyData>();
            replys.add(reply);
            return replys;
        }                 

        if (args == null) {
            _bc.logInfo(_bmr.getString(_bmr.I_LISTING_BRIDGE, name), null);
        } else {
            _bc.logInfo(_bmr.getString(_bmr.I_LISTING_BRIDGE_WITH, name, BridgeContext.toString(args)), null);
        }

        Bridge b = _bridges.get(name);
        if (b == null) { 
            String emsg = _bmr.getKString(_bmr.X_BRIDGE_NAME_NOT_FOUND, name);
            _bc.logError(emsg, null);
            throw new BridgeException(emsg);
        }

        BridgeContext bc = new BridgeContext(_bc, b.getName());
        return b.list(bc, args, bmr);
    }

    /**
     * Stop the bridge service manager
     */
    public void stop() throws Exception {
        if (_state == State.STOPPING || _state == State.STOPPED) {
            return;
        }
        synchronized(this) {

        if (_bc == null) {
            throw new BridgeException(_bmr.getString(_bmr.X_BRIDGE_SERVICE_MANAGER_NOT_INITED));
        }
        _state = State.STOPPING;
        try {
            stopBridge(null, null, null);
        } catch (Throwable t) {
            if (t instanceof java.util.concurrent.RejectedExecutionException) {
            _bc.logDebug(_bmr.getKString(_bmr.W_EXCEPTION_STOP_BRIDGES, t.getMessage()), null);
            } else {
            _bc.logWarn(_bmr.getKString(_bmr.W_EXCEPTION_STOP_BRIDGES, t.getMessage()), t);
            }
        }

        if (_connection != null) {
            try {
            _connection.close();
            } catch (Throwable t) {
            if (DEBUG) {
            _bc.logWarn(_bmr.getKString(_bmr.W_EXCEPTION_CLOSE_ADMIN_CONN, t.getMessage()), t);
            } else {
            _bc.logWarn(_bmr.getKString(_bmr.W_EXCEPTION_CLOSE_ADMIN_CONN, t.getMessage()), null);
            }
            }
        }
        _state = State.STOPPED;

        }
    }

    /**
     *
     */
    public Bridge getBridge(String name) throws Exception {
        Bridge b = _bridges.get(name);
        if (b == null) { 
            throw new BridgeException(_bmr.getKString(_bmr.X_BRIDGE_NAME_NOT_FOUND, name));
        }
        return b;
    }

    public BridgeBaseContext getBridgeBaseContext() {
        return _bc;
    }

    public void onException(JMSException e) {
        if (_bc.isEmbeded()) {
            _bc.logError(_bmr.getKString(_bmr.E_EXCEPTION_OCCURRED_ADMIN_CONN, e.getMessage()), e);
        } else {
            //not supported else do reconnect   
            _bc.logError("Not supported: bridge servie manager is not embeded!", null);
        }
    }

    public void onMessage(Message msg) {

        if (_state != State.STARTED) {
            String emsg = _bmr.getKString(_bmr.X_BRIDGE_SERVICE_MANAGER_NOT_RUNNING);
            _bc.logInfo(emsg, null);
            _adminHandler.sendReply(_session, msg, null, Status.UNAVAILABLE, emsg, _bmr);
        }
        if (!(msg instanceof ObjectMessage)) {
            String emsg = "Unexpected bridge admin message type: "+msg.getClass().getName();
            _bc.logError(emsg, null);
            _adminHandler.sendReply(_session, msg, null, Status.BAD_REQUEST, emsg, _bmr);
            return;
        }
        _adminHandler.handle(_session, (ObjectMessage)msg);
    }

    public static BridgeManagerResources getBridgeManagerResources() {
        if (_bmr == null) {
            synchronized(BridgeServiceManagerImpl.class) {
                if (_bmr == null) {
                    _bmr = BridgeManagerResources.getResources(Locale.getDefault());
                }
            }
        }
        return _bmr;
    }

    public static BridgeManagerResources getBridgeManagerResources(Locale l) {
        if (l == null) return getBridgeManagerResources();

        BridgeManagerResources bmr = _bmrs.get(l);
        if (bmr != null) return bmr;

        synchronized(_bmrs) {
            bmr = _bmrs.get(l);
            if (bmr == null) {
                bmr = BridgeManagerResources.getResources(l);
                _bmrs.put(l, bmr);
            }
            return bmr;
        }
    }

    public boolean getDEBUG() {
        return DEBUG;
    }

    public static void main(String[] args) {
    }
}
