/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999-2012 Bull S.A.S.
 * Contact: jonas-team@ow2.org
 *
 * This library 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 any later version.
 *
 * 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser 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
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.ow2.jonas.security.internal;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.Reader;
import java.io.StringReader;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;

import javax.management.MalformedObjectNameException;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.security.jacc.PolicyContext;
import javax.security.jacc.PolicyContextException;
import javax.security.jacc.PolicyContextHandler;

import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;
import org.ow2.carol.rmi.interceptor.spi.JInitializer;
import org.ow2.carol.util.configuration.ConfigurationException;
import org.ow2.carol.util.configuration.ConfigurationRepository;
import org.ow2.jonas.jmx.JmxService;
import org.ow2.jonas.lib.security.jacc.handlers.JPolicyContextHandler;
import org.ow2.jonas.lib.service.AbsConfigServiceImpl;
import org.ow2.jonas.lib.service.AbsServiceImpl;
import org.ow2.jonas.lib.util.JonasObjectName;
import org.ow2.jonas.lib.util.Log;
import org.ow2.jonas.registry.RegistryService;
import org.ow2.jonas.security.SecurityService;
import org.ow2.jonas.security.interceptors.jrmp.SecurityInitializer;
import org.ow2.jonas.security.interceptors.jrmp.ctxcheck.Initializer;
import org.ow2.jonas.security.internal.realm.factory.JResourceDS;
import org.ow2.jonas.security.internal.realm.factory.JResourceLDAP;
import org.ow2.jonas.security.internal.realm.factory.JResourceMemory;
import org.ow2.jonas.security.internal.realm.factory.JResourceRemoteImpl;
import org.ow2.jonas.security.internal.realm.lib.HashHelper;
import org.ow2.jonas.security.internal.realm.principal.Group;
import org.ow2.jonas.security.internal.realm.principal.Role;
import org.ow2.jonas.security.lib.JResourceManager;
import org.ow2.jonas.security.realm.factory.JResource;
import org.ow2.jonas.security.realm.principal.JUser;
import org.ow2.jonas.service.ServiceException;

/**
 * Security Service implementation?
 * @author Jeff Mesnil,Philippe Coq, John Ellis, Joe Gittings for old security
 *         service
 * @author Florent Benoit - JOnAS 3.x (Add JResources) - JOnAS 4.x (remove
 *         MethodGuard, RoleGuard no more used with JACC)
 */
public class JonasSecurityServiceImpl extends AbsConfigServiceImpl implements SecurityService, JonasSecurityServiceImplMBean {

    /**
     * Logger which is used.
     */
    private static Logger logger = Log.getLogger(Log.JONAS_SECURITY_PREFIX);

    /**
     * Name of resource.
     */
    public static final String REMOTE_RESOUCE = "_remoteres";

    /**
     * Name of the realm configuration file
     */
    protected static final String REALM_CONFIG_FILENAME = "jonas-realm.xml";

    /**
     * Relative path of the realm configuration file.
     * TODO to be removed when JOnAS'll be assembled with addons
     */
    protected static final String CONFIG_FILE = "conf" + File.separator + REALM_CONFIG_FILENAME;

    /**
     * Property for the security propagation.
     */
    private static final String SECURITY_PROPAGATION = "jonas.security.propagation";

    /**
     * Reference to the jmx service.
     */
    private JmxService jmxService = null;

    /**
     * Registry Service.
     */
    private RegistryService registryService;

    /**
     * JResources list.
     */
    private JResources jResources;

    /**
     * Initial Context for Naming.
     */
    private Context ictx = null;

    /**
     * Bind resource in JNDI.
     */
    private boolean bindResourcesIntoJndi = false;

    /**
     * List of registered JRMP interceptors.
     */
    private List<Class<? extends JInitializer>> jrmpInterceptors = null;

    /**
     * Property for the security context check.
     */
    private boolean contextCheckEnable;

    /**
     * @param register Bind a resource for security in JNDI ?
     */
    public void setRealmJndiRegistration(final boolean register) {
        this.bindResourcesIntoJndi = register;
    }

    /**
     * @param contextCheckEnable True if the security context check on Remote Login Module is enable
     */
    public void setContextCheck(final boolean contextCheckEnable) {
        this.contextCheckEnable = contextCheckEnable;
    }

    /**
     * Remove the Resource (memory, ldap, datasource,...).
     * @param resourceName name of the resource
     * @throws Exception if the resource name does not exist
     */
    public void removeJResource(final String resourceName) throws Exception {

        // remove the given resource of the list
        JResource jResource = jResources.remove(resourceName);

        // remove the resource into the jndi
        if (bindResourcesIntoJndi) {
            try {
                ictx.unbind(resourceName);
                if (logger.isLoggable(BasicLevel.DEBUG)) {
                    logger.log(BasicLevel.DEBUG, "jResource " + resourceName + " remove from the registry.");
                }
            } catch (NamingException e) {
                logger.log(BasicLevel.ERROR, "Cannot unbind the resource '" + resourceName + "' into JNDI", e);
            }
        }

        try {
            // Remove mbeans of the resources
            jResource.removeMBeans();

            // register security factory mbean
            if (jResource instanceof JResourceMemory) {
                jmxService.unregisterModelMBean(JonasObjectName.securityMemoryFactory(getDomainName(), resourceName));
            } else if (jResource instanceof JResourceDS) {
                jmxService.unregisterModelMBean(JonasObjectName.securityDatasourceFactory(getDomainName(), resourceName));
            } else if (jResource instanceof JResourceLDAP) {
                jmxService.unregisterModelMBean(JonasObjectName.securityLdapFactory(getDomainName(), resourceName));
            }
        } catch (ServiceException se) {
            logger.log(BasicLevel.ERROR, "JMX service not available", se);
        } catch (Exception e) {
            logger.log(BasicLevel.ERROR, "Can not unregister the MBean for the resource " + resourceName + " : "
                    + e.getMessage());
            throw new ServiceException("Can not unregister the MBean for the resource " + resourceName + " : "
                    + e.getMessage());
        }

    }

    /**
     * @param registry the registry service to set
     */
    public void setRegistryService(final RegistryService registry) {
        this.registryService = registry;
    }

    /**
     * Returns the registry service.
     * @return The registry service
     */
    private RegistryService getRegistryService() {
        return registryService;
    }

    /**
     * Initialize the context handlers (JACC).
     * @throws PolicyContextException if handlers can't be registered
     */
    private void initJACCPolicyContextHandlers() throws PolicyContextException {
        logger.log(BasicLevel.DEBUG, "");
        PolicyContextHandler policyContextHandler = new JPolicyContextHandler();
        String[] keys = policyContextHandler.getKeys();
        for (int k = 0; k < keys.length; k++) {
            logger.log(BasicLevel.DEBUG, "key " + keys[k]);
            PolicyContext.registerHandler(keys[k], policyContextHandler, true);
        }
    }

    /**
     * Start the Service Initialization of the service is already done.
     * @throws ServiceException if the stop failed.
     */
    @Override
    public void doStart() throws ServiceException {
        jrmpInterceptors = new ArrayList<Class<? extends JInitializer>>();

        try {
            boolean security = Boolean.parseBoolean(getServerProperties().getValue(SECURITY_PROPAGATION));
            if (security) {
                jrmpInterceptors.add(SecurityInitializer.class);
                // Assert security context ?
                if (this.contextCheckEnable) {
                    jrmpInterceptors.add(Initializer.class);
                }
            }

            for (Class<? extends JInitializer> interceptor : jrmpInterceptors) {
                ConfigurationRepository.addInterceptors("jrmp", interceptor);
            }

        } catch (ConfigurationException e) {
            throw new ServiceException("Cannot init security interceptors for Carol", e);
        }


        // In OSGi, this is the security service and not the Server class
        // That is initializing the Policy Stuff
        // Set the security policy if defined.
        PolicyProvider.init();
        try {
            initJACCPolicyContextHandlers();
        } catch (PolicyContextException e1) {
            logger.log(BasicLevel.ERROR, "Cannot init JACCPolicyContextHandlers");
            throw new ServiceException("Cannot init JACCPolicyContextHandlers :" + e1);
        }

        try {
            final SecurityService ss = this;
            jResources = new JResources();
            jResources.setSecurityService(ss);

            // Get the InitialContext
            try {
                JResourceRemoteImpl jrri = new JResourceRemoteImpl(ss);

                ictx = getRegistryService().getRegistryContext();
                // Register security remote object (name based on JOnAS
                // server name).
                ictx.rebind(getJonasServerName() + REMOTE_RESOUCE, jrri);
            } catch (Exception e) {
                // Throw an ServiceException if needed
                logger.log(BasicLevel.ERROR, "Cannot create initial context when Security service initializing");
                throw new ServiceException("Cannot create initial context when Security service initializing", e);
            }

            // register security service mbean
            jmxService.registerMBean(this, JonasObjectName.securityService(getDomainName()));
        } catch (ServiceException se) {
            logger.log(BasicLevel.ERROR, "JMX service not available", se);
        } catch (Throwable e) {
            logger.log(BasicLevel.ERROR, "SecurityService: Cannot start the Security service:\n" + e);

            e.printStackTrace();
            throw new ServiceException("SecurityService: Cannot start the Security service", e);
        }
        createRealm();
        try {
            registerResourcesMBeans();
        } catch (MalformedObjectNameException e) {
            throw new ServiceException("SecurityService: Cannot register mbeans", e);
        }
        logger.log(BasicLevel.INFO, "Security Service started");
    }


    /**
     * Look for JResourceMemory resources as they are the only security
     * resources (for the moment) which have associated MBeans.
     * @throws MalformedObjectNameException ObjectName could not be created
     */
    private void registerResourcesMBeans() throws MalformedObjectNameException {
        Enumeration<JResource> resourcesEnum = jResources.getResources();
        String domainName = getDomainName();
        while (resourcesEnum.hasMoreElements()) {
            JResource aResource = resourcesEnum.nextElement();
            if (aResource instanceof JResourceMemory) {
                String resourceName = aResource.getName();
                JResourceMemory aResourceMemory = (JResourceMemory) aResource;

                // needed for later jonasadmin actions
                aResourceMemory.setJmxService(jmxService);
                aResourceMemory.setDomainName(domainName);
                aResourceMemory.setSecurityService(this);

                // get users
                Hashtable<String, JUser> usersTable = aResourceMemory.getUsers();
                Enumeration<String> userNames = usersTable.keys();
                while (userNames.hasMoreElements()) {
                    String userName = userNames.nextElement();
                    JUser user = usersTable.get(userName);
                    
                    // Replace ,= character if it's a DN
                    userName = userName.replace("=", "#"); 
                    userName = userName.replace(",", "#"); 
                    jmxService.registerMBean(user, JonasObjectName.user(domainName, resourceName, userName));
                }
                // get groups
                Hashtable<String, Group> groupsTable = aResourceMemory.getGroups();
                Enumeration<String> groupNames = groupsTable.keys();
                while (groupNames.hasMoreElements()) {
                    String groupName = groupNames.nextElement();
                    Group group = groupsTable.get(groupName);
                    jmxService.registerMBean(group, JonasObjectName.group(domainName, resourceName, groupName));
                }
                // get roles
                Hashtable<String, Role> rolesTable = aResourceMemory.getRoles();
                Enumeration<String> roleNames = rolesTable.keys();
                while (roleNames.hasMoreElements()) {
                    String roleName = roleNames.nextElement();
                    Role role = rolesTable.get(roleName);
                    jmxService.registerMBean(role, JonasObjectName.role(domainName, resourceName, roleName));
                }
            }
        }
    }

    /**
     * Stop the Service.
     */
    @Override
    public void doStop() {
        // jmxService may be null if the component deactivation is due to the unregistering of the jmxService
        if (jmxService != null) {
            // Remove JResources
            try {
                removeJResources();
            } catch (Exception e) {
                logger.log(BasicLevel.ERROR, "Cannot remove JResources", e);
            }

            // Unregister MBean
            jmxService.unregisterMBean(JonasObjectName.securityService(getDomainName()));
        }

        // Unregister the security remote object (name is based on JOnAS server
        // name).
        try {
            ictx.unbind(getJonasServerName() + REMOTE_RESOUCE);
        } catch (Exception e) {
            logger.log(BasicLevel.ERROR, "Cannot unbind remote resource for security access", e);
            throw new ServiceException("Cannot unbind remote resource for security access", e);
        }

        try {
            for (Class<? extends JInitializer> interceptor : jrmpInterceptors) {
                ConfigurationRepository.removeInterceptors("jrmp", interceptor);
            }
            jrmpInterceptors.clear();
        } catch (ConfigurationException e) {
            throw new ServiceException("Cannot remove security interceptors for Carol", e);
        }
        logger.log(BasicLevel.INFO, "Security Service stopped");
    }

    /**
     * Unregister all previously registered Resources MBeans.
     * @throws Exception if error occurs
     */
    private void removeJResources() throws Exception {
        Enumeration<JResource> resourcesEnum = jResources.getResources();
        while (resourcesEnum.hasMoreElements()) {
            JResource aResource = resourcesEnum.nextElement();
            removeJResource(aResource.getName());
        }
    }

    /**
     * Return a resource by giving its name.
     * @param name the wanted Resource
     * @return a JResouce
     */
    public JResource getJResource(final String name) {
        return jResources.getJResource(name);
    }

    /**
     * Parse the xml file and create all the JResource.
     * @throws ServiceException if a JResource can't be created
     */
    private void createRealm() throws ServiceException {

        // Execute the digester for the parsing of the jonas-realm.xml file.
        File configFile = null;
        Reader reader = null;
        try {
            configFile = getConfigFile();
            reader = new FileReader(configFile);
        } catch (FileNotFoundException e) {
            logger.log(BasicLevel.ERROR, "Cannot find config file " + configFile);
            throw new ServiceException(e.getMessage(), e);
        }

        try {
            JResourceManager resourceManager = JResourceManager.getInstance();
            resourceManager.addResources(jResources, reader, configFile.getPath());

        } catch (Throwable e) {
            String err = "Cannot add security resource from '" + configFile + "'";
            logger.log(BasicLevel.ERROR, err);
            throw new ServiceException(err, e);
        }
    }

    /**
     * Return a File object representing the jonas-realm.xml configuration file.
     * @return a File object representing the jonas-realm.xml configuration file.
     * @throws FileNotFoundException if the configuration file is not found.
     */
    protected File getConfigFile() throws FileNotFoundException {

        if (this.addonConfig != null) {
            return this.addonConfig.getConfigurationFile(REALM_CONFIG_FILENAME);
        }

        String fileName = System.getProperty("jonas.base");
        fileName = fileName + File.separator + CONFIG_FILE;
        File file = new File(fileName);
        if (!file.exists()) {
            String err = "Can't find configuration file : " + fileName;
            throw new FileNotFoundException(err);
        }
        return (file);
    }

    /**
     * String representation of the JOnAS realm.
     * @return the xml representation of the JOnAS realm
     */
    public String toXML() {
        return jResources.toXML();
    }

    /**
     * Encrypt a string with an algorithm.
     * @param string the string to encode
     * @param algo algorithm to apply on the given string
     * @return the encoded string
     * @throws NoSuchAlgorithmException One reason could be a bad algorithm
     */
    public String encryptPassword(final String string, final String algo) throws NoSuchAlgorithmException {
        String encrypt = HashHelper.hashPassword(string, algo);
        // Prefix with algorithm
        return "{" + algo.toUpperCase() + "}" + encrypt;
    }

    /**
     * Check if the given algorithm is a valid algorithm.
     * @param algo algorithm to apply on the given string
     * @return true if it is a valid algorithm
     */
    public boolean isValidAlgorithm(final String algo) {
        boolean b = true;
        try {
            encryptPassword("test", algo);
        } catch (NoSuchAlgorithmException nsae) {
            b = false;
        }
        return b;
    }

    /**
     * Add JResources with a given xml configuration.
     * @param xml xml representation of the resources to add
     * @throws Exception if the resources can't be added
     */
    public void addResources(final String xml) throws Exception {
        try {
            // No need to use the wrapper, because class loader hierarchy has been
            // removed by OSGi.
            JResourceManager resourceManager = JResourceManager.getInstance();
            if (!resourceManager.hasJmxService()) {
                resourceManager.setJmxService(jmxService);
                resourceManager.setDomainName(getDomainName());
            }
            resourceManager.addResources(jResources, new StringReader(xml), "");
        } catch (Exception e1) {
            String err = "Cannot add security resource from xml '" + xml + "'";
            logger.log(BasicLevel.ERROR, err);
            throw new ServiceException(err, e1);
        }
    }

    /**
     * Add a Memory resource.
     * @param name the name of the JResourceMemory to create
     * @throws Exception if the resource can't be added
     */
    public void addJResourceMemory(final String name) throws Exception {

        // Build a new JResourceMemory
        JResourceMemory jResourceMemory = new JResourceMemory();
        jResourceMemory.setSecurityService(this);
        jResourceMemory.setJmxService(jmxService);
        jResourceMemory.setDomainName(getDomainName());

        jResourceMemory.setName(name);

        // Build xml
        StringBuffer xml = new StringBuffer(JResources.HEADER_XML);
        xml.append("<jonas-realm>");
        xml.append("<jonas-memoryrealm>");
        xml.append(jResourceMemory.toXML());
        xml.append("</jonas-memoryrealm>");
        xml.append("</jonas-realm>");

        // Add the resource
        addResources(xml.toString());

    }

    /**
     * Add a DS resource.
     * @param name the name of the JResourceDS to create
     * @param dsName Name of the datasource resource to use.
     * @param userTable Name of table which have the username/password
     * @param userTableUsernameCol Column of the username of the user table
     * @param userTablePasswordCol Column of the password of the user table
     * @param roleTable Name of table which have the username/role
     * @param roleTableUsernameCol Column of the username of the role table
     * @param roleTableRolenameCol Column of the role of the role table
     * @param algorithm Default algorithm. If specified, the default is not
     *        'clear' password
     * @throws Exception if the resource can't be added
     */
    public void addJResourceDS(final String name, final String dsName, final String userTable,
            final String userTableUsernameCol, final String userTablePasswordCol, final String roleTable,
            final String roleTableUsernameCol, final String roleTableRolenameCol, final String algorithm) throws Exception {

        // Build a new JResourceDS
        JResourceDS jResourceDS = new JResourceDS();
        jResourceDS.setSecurityService(this);
        jResourceDS.setJmxService(jmxService);
        jResourceDS.setDomainName(getDomainName());

        jResourceDS.setName(name);
        jResourceDS.setDsName(dsName);
        jResourceDS.setUserTable(userTable);
        jResourceDS.setUserTableUsernameCol(userTableUsernameCol);
        jResourceDS.setUserTablePasswordCol(userTablePasswordCol);
        jResourceDS.setRoleTable(roleTable);
        jResourceDS.setRoleTableUsernameCol(roleTableUsernameCol);
        jResourceDS.setRoleTableRolenameCol(roleTableRolenameCol);
        jResourceDS.setAlgorithm(algorithm);

        // Build xml
        StringBuffer xml = new StringBuffer(JResources.HEADER_XML);
        xml.append("<jonas-realm>");
        xml.append("<jonas-dsrealm>");
        xml.append(jResourceDS.toXML());
        xml.append("</jonas-dsrealm>");
        xml.append("</jonas-realm>");

        // Add the resource
        addResources(xml.toString());

    }

    /**
     * Add a LDAP resource.
     * @param name the name of the JResourceLDAP to create
     * @param initialContextFactory Initial context factory for the LDAp server
     * @param providerUrl Url of the ldap server
     * @param securityAuthentication Type of the authentication used during the
     *        authentication to the LDAP server
     * @param securityPrincipal DN of the Principal(username). He can retrieve
     *        the information from the user
     * @param securityCredentials Credential(password) of the principal
     * @param securityProtocol Constant that holds the name of the environment
     *        property for specifying the security protocol to use.
     * @param language Constant that holds the name of the environment property
     *        for specifying the preferred language to use with the service.
     * @param referral Constant that holds the name of the environment property
     *        for specifying how referrals encountered by the service provider
     *        are to be processed.
     * @param stateFactories Constant that holds the name of the environment
     *        property for specifying the list of state factories to use.
     * @param authenticationMode Mode for validate the authentication
     *        (BIND_AUTHENTICATION_MODE or COMPARE_AUTHENTICATION_MODE)
     * @param userPasswordAttribute Attribute in order to get the password from
     *        the ldap server
     * @param userRolesAttribute Attribute in order to get the user role from
     *        the ldap server
     * @param roleNameAttribute Attribute for the role name when performing a
     *        lookup on a role
     * @param baseDN DN used for the lookup
     * @param userDN DN used when searching the user DN. Override the baseDN if
     *        it is defined
     * @param userSearchFilter Filter used when searching the user
     * @param roleDN DN used when searching the role DN. Override the baseDN if
     *        it is defined
     * @param roleSearchFilter Filter used when searching the role
     * @param algorithm Default algorithm. If specified, the default is not
     *        'clear' password
     * @throws Exception if the resource can't be added
     */
    public void addJResourceLDAP(final String name, final String initialContextFactory, final String providerUrl,
            final String securityAuthentication, final String securityPrincipal, final String securityCredentials,
            final String securityProtocol, final String language, final String referral, final String stateFactories,
            final String authenticationMode, final String userPasswordAttribute, final String userRolesAttribute,
            final String roleNameAttribute, final String baseDN, final String userDN, final String userSearchFilter,
            final String roleDN, final String roleSearchFilter, final String algorithm) throws Exception {

        // Build a new JResourceLDAP
        JResourceLDAP jResourceLDAP = new JResourceLDAP();
        jResourceLDAP.setSecurityService(this);
        jResourceLDAP.setJmxService(jmxService);
        jResourceLDAP.setDomainName(getDomainName());

        jResourceLDAP.setName(name);
        jResourceLDAP.setInitialContextFactory(initialContextFactory);
        jResourceLDAP.setProviderUrl(providerUrl);
        jResourceLDAP.setSecurityAuthentication(securityAuthentication);
        jResourceLDAP.setSecurityPrincipal(securityPrincipal);
        jResourceLDAP.setSecurityCredentials(securityCredentials);
        jResourceLDAP.setSecurityProtocol(securityProtocol);
        jResourceLDAP.setLanguage(language);
        jResourceLDAP.setReferral(referral);
        jResourceLDAP.setStateFactories(stateFactories);
        jResourceLDAP.setAuthenticationMode(authenticationMode);
        jResourceLDAP.setUserPasswordAttribute(userPasswordAttribute);
        jResourceLDAP.setUserRolesAttribute(userRolesAttribute);
        jResourceLDAP.setRoleNameAttribute(roleNameAttribute);
        jResourceLDAP.setBaseDN(baseDN);
        jResourceLDAP.setUserDN(userDN);
        jResourceLDAP.setUserSearchFilter(userSearchFilter);
        jResourceLDAP.setRoleDN(roleDN);
        jResourceLDAP.setRoleSearchFilter(roleSearchFilter);
        jResourceLDAP.setAlgorithm(algorithm);

        // Build xml
        StringBuffer xml = new StringBuffer(JResources.HEADER_XML);
        xml.append("<jonas-realm>");
        xml.append("<jonas-ldaprealm>");
        xml.append(jResourceLDAP.toXML());
        xml.append("</jonas-ldaprealm>");
        xml.append("</jonas-realm>");

        // Add the resource
        addResources(xml.toString());

    }

    /**
     * Bind the given resource with the given name and register with a new
     * MBean.
     * @param name resource name
     * @param jResource resource
     */
    public void bindResource(final String name, final JResource jResource) {
        // bind the resource into the jndi
        if (bindResourcesIntoJndi) {
            try {
                ictx.rebind(jResource.getName(), jResource);
                if (logger.isLoggable(BasicLevel.DEBUG)) {
                    logger.log(BasicLevel.DEBUG, "jResource " + jResource.getName() + " bound into the registry.");
                }
            } catch (NamingException e) {
                logger.log(BasicLevel.ERROR, "Cannot bind the resource '" + jResource.getName() + "' into JNDI", e);
            }
        }

        try {
            // register security factory mbean
            if (jResource instanceof JResourceMemory) {
                jmxService
                        .registerModelMBean(jResource, JonasObjectName.securityMemoryFactory(getDomainName(), jResource.getName()));
            } else if (jResource instanceof JResourceDS) {
                jmxService.registerModelMBean(jResource, JonasObjectName.securityDatasourceFactory(getDomainName(), jResource
                        .getName()));
            } else if (jResource instanceof JResourceLDAP) {
                jmxService.registerModelMBean(jResource, JonasObjectName.securityLdapFactory(getDomainName(), jResource.getName()));
            }
        } catch (ServiceException se) {
            logger.log(BasicLevel.ERROR, "JMX service not available", se);
        } catch (Exception e) {
            logger.log(BasicLevel.ERROR, "Can not register the MBean for the resource " + jResource.getName() + " : "
                    + e.getMessage());
            throw new ServiceException("Can not register the MBean for the resource " + jResource.getName() + " : "
                    + e.getMessage());
        }

    }

    /**
     * @param jmxService the jmxService to set
     */
    public void setJmxService(final JmxService jmxService) {
        this.jmxService = jmxService;
    }
}
