org.sipfoundry.sipxconfig.bulk.ldap.LdapManagerImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.sipfoundry.sipxconfig.bulk.ldap.LdapManagerImpl.java

Source

/*
 *
 *
 * Copyright (C) 2007 Pingtel Corp., certain elements licensed under a Contributor Agreement.
 * Contributors retain copyright to elements licensed under a Contributor Agreement.
 * Licensed to the User under the LGPL license.
 *
 * $
 */
package org.sipfoundry.sipxconfig.bulk.ldap;

import static org.springframework.dao.support.DataAccessUtils.singleResult;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import javax.naming.directory.SearchControls;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sipfoundry.sipxconfig.common.CronSchedule;
import org.sipfoundry.sipxconfig.common.SipxHibernateDaoSupport;
import org.sipfoundry.sipxconfig.common.UserException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.ldap.AttributesMapper;
import org.springframework.ldap.UncategorizedLdapException;

/**
 * Maintains LDAP connection params, attribute maps and schedule LdapManagerImpl
 */
public class LdapManagerImpl extends SipxHibernateDaoSupport implements LdapManager, ApplicationContextAware {
    private static final Log LOG = LogFactory.getLog(LdapManagerImpl.class);
    private static final String NAMING_CONTEXTS = "namingContexts";
    private static final String SUBSCHEMA_SUBENTRY = "subschemaSubentry";
    private LdapTemplateFactory m_templateFactory;
    private ApplicationContext m_applicationContext;

    public void verify(LdapConnectionParams params, AttrMap attrMap) {
        try {
            String[] attrNames = new String[] { NAMING_CONTEXTS, SUBSCHEMA_SUBENTRY };
            Map<String, String> results = retrieveDefaultSearchBase(params, attrNames);

            String searchBase = results.get(attrNames[0]).trim();
            // it will only overwrite the search base if not set yet
            if (StringUtils.isBlank(attrMap.getSearchBase()) && StringUtils.isNotEmpty(searchBase)) {
                attrMap.setSearchBase(searchBase);
            }
            attrMap.setSearchBaseDefault(searchBase);
            String subschemaSubentry = results.get(attrNames[1]);
            attrMap.setSubschemaSubentry(subschemaSubentry);
        } catch (NamingException e) {
            verifyException("&readData.failed", e);
        } catch (DataAccessException e) {
            verifyException("&connection.failed", e);
        }
    }

    public boolean verifyLdapConnection(LdapConnectionParams params) {
        LOG.debug("verifying LDAP connection: " + params.getFullHost());
        try {
            String[] attrNames = new String[] { NAMING_CONTEXTS, SUBSCHEMA_SUBENTRY };
            retrieveDefaultSearchBase(params, attrNames);
            return true;
        } catch (NamingException e) {
            return false;
        } catch (DataAccessException e) {
            return false;
        }
    }

    public boolean verifyAllLdapConnections() {
        LOG.debug("verifying all LDAP connections");
        List<LdapConnectionParams> connParams = getAllConnectionParams();
        for (LdapConnectionParams params : connParams) {
            if (!verifyLdapConnection(params)) {
                continue;
            } else {
                return true;
            }
        }
        return false;
    }

    private void verifyException(String message, Exception e) {
        LOG.debug("Verifying LDAP connection failed.", e);
        // for the purpose of readability, remove any nested exception
        // info from the message, if there is any. This is done by only
        // taking that part of the message up to the first ';'
        String fullMessage = e.getMessage();
        String parsedMessage = fullMessage;
        if (fullMessage.indexOf(';') > 0) {
            parsedMessage = fullMessage.substring(0, fullMessage.indexOf(';'));
        }
        throw new UserException(message, parsedMessage);
    }

    public Schema getSchema(String subschemaSubentry, LdapConnectionParams params) {
        try {
            SearchControls cons = new SearchControls();
            // only interested in the first result
            cons.setCountLimit(1);
            // set time limit for this search to 30 sec, should be sufficient even for large LDAPs
            cons.setTimeLimit(30000);

            SchemaMapper mapper = new SchemaMapper();
            cons.setReturningAttributes(mapper.getReturningAttributes());
            cons.setSearchScope(SearchControls.OBJECT_SCOPE);

            Schema schema = (Schema) m_templateFactory.getLdapTemplate(params).search(subschemaSubentry,
                    LdapManager.FILTER_ALL_CLASSES, cons, new SchemaMapper(), LdapManager.NULL_PROCESSOR).get(0);

            return schema;
        } catch (DataIntegrityViolationException e) {
            LOG.debug("Retrieving schema failed.", e);
            throw new UserException("searchSchema.violation.error");
        } catch (UncategorizedLdapException e) {
            LOG.debug("Retrieving schema failed. Anonymous-binding may be disabled", e);
            throw new UserException("searchSchema.anonymousBinding.error");
        }
    }

    private static class SchemaMapper implements AttributesMapper {
        private final Schema m_schema;
        private boolean m_initialized;

        SchemaMapper() {
            m_schema = new Schema();
        }

        public String[] getReturningAttributes() {
            return new String[] { "objectClasses" };
        }

        public Object mapFromAttributes(Attributes attributes) throws NamingException {
            // only interested in the first result
            if (!m_initialized) {
                NamingEnumeration definitions = attributes.get(getReturningAttributes()[0]).getAll();
                while (definitions.hasMoreElements()) {
                    String classDefinition = (String) definitions.nextElement();
                    m_schema.addClassDefinition(classDefinition);
                }
                m_initialized = true;
            }
            return m_schema;
        }
    }

    /**
     * Connects to LDAP to retrieve the namingContexts attribute from root. Good
     * way to verify if LDAP is accessible. Command line anologue is:
     *
     * ldapsearch -x -b '' -s base '(objectclass=*)' namingContexts
     *
     * @param attrNames
     *            TODO
     *
     * @return namingContext value - can be used as the search base for user if
     *         nothing more specific is provided
     * @throws NamingException
     */
    private Map<String, String> retrieveDefaultSearchBase(LdapConnectionParams params, String[] attrNames)
            throws NamingException {

        SearchControls cons = new SearchControls();

        cons.setReturningAttributes(attrNames);
        cons.setSearchScope(SearchControls.OBJECT_SCOPE);
        cons.setTimeLimit(30000);

        List<Map<String, String>> results = m_templateFactory.getLdapTemplate(params).search("", FILTER_ALL_CLASSES,
                cons, new AttributesToValues(attrNames), NULL_PROCESSOR);
        // only interested in the first result
        if (results.size() > 0) {
            return results.get(0);
        }
        return null;
    }

    static class AttributesToValues implements AttributesMapper {
        private final String[] m_attrNames;

        public AttributesToValues(String... attrNames) {
            m_attrNames = attrNames;
        }

        public Map<String, String> mapFromAttributes(Attributes attributes) throws NamingException {
            Map<String, String> values = new HashMap<String, String>();
            for (String attrName : m_attrNames) {
                // only retrieves a single value for each attribute
                Object value = attributes.get(attrName).get();
                values.put(attrName, value.toString());
            }
            return values;
        }
    }

    public CronSchedule getSchedule(int connectionId) {
        return getConnectionParams(connectionId).getSchedule();
    }

    public void setSchedule(CronSchedule schedule, int connectionId) {
        if (!schedule.isNew()) {
            // XCF-1168 incoming schedule is probably an update to this schedule
            // so add this schedule to cache preempt hibernate error about
            // multiple
            // objects with same ID in session. This is only true because
            // schedule
            // is managed by LdapConnectionParams object.
            getHibernateTemplate().update(schedule);
        }

        LdapConnectionParams connectionParams = getConnectionParams(connectionId);
        connectionParams.setSchedule(schedule);
        getHibernateTemplate().update(connectionParams);
        getDaoEventPublisher().publishSave(connectionParams);
        m_applicationContext.publishEvent(new LdapImportTrigger.ScheduleChangedEvent(schedule, this, connectionId));
    }

    public AttrMap getAttrMap(int connectionId) {
        List<AttrMap> connectionsAttrMap = getHibernateTemplate()
                .findByNamedQueryAndNamedParam("ldapConnectionAttrMap", "attrMapId", connectionId);
        if (!connectionsAttrMap.isEmpty()) {
            return connectionsAttrMap.get(0);
        }
        return createAttrMap();
    }

    public LdapConnectionParams getConnectionParams(int connectionId) {
        List<LdapConnectionParams> connections = getHibernateTemplate()
                .findByNamedQueryAndNamedParam("ldapConnection", "connectionId", connectionId);
        if (!connections.isEmpty()) {
            return connections.get(0);
        }
        return createConnectionParams();
    }

    public LdapConnectionParams createConnectionParams() {
        LdapConnectionParams params = (LdapConnectionParams) m_applicationContext.getBean("ldapConnectionParams",
                LdapConnectionParams.class);
        return params;
    }

    public AttrMap createAttrMap() {
        return (AttrMap) m_applicationContext.getBean("attrMap", AttrMap.class);
    }

    public List<LdapConnectionParams> getAllConnectionParams() {
        return getHibernateTemplate().loadAll(LdapConnectionParams.class);
    }

    public void setAttrMap(AttrMap attrMap) {
        getHibernateTemplate().merge(attrMap);
        getDaoEventPublisher().publishSave(attrMap);
    }

    public void saveSystemSettings(LdapSystemSettings settings) {
        getHibernateTemplate().saveOrUpdate(settings);
    }

    public LdapSystemSettings getSystemSettings() {
        List settingses = getHibernateTemplate().loadAll(LdapSystemSettings.class);
        LdapSystemSettings settings = (LdapSystemSettings) singleResult(settingses);
        if (settings == null) {
            settings = (LdapSystemSettings) m_applicationContext.getBean("ldapSystemSettings",
                    LdapSystemSettings.class);
        }
        return settings;
    }

    public void setConnectionParams(LdapConnectionParams params) {
        getHibernateTemplate().saveOrUpdate(params);
        getDaoEventPublisher().publishSave(params);
    }

    public void removeConnectionParams(int connectionId) {
        LdapConnectionParams params = getConnectionParams(connectionId);
        getHibernateTemplate().delete(params);
        getHibernateTemplate().delete(getAttrMap(connectionId));
        getDaoEventPublisher().publishDelete(params);
        m_applicationContext.publishEvent(new LdapImportTrigger.ScheduleDeletedEvent(this, connectionId));
    }

    public void setApplicationContext(ApplicationContext applicationContext) {
        m_applicationContext = applicationContext;
    }

    public void setTemplateFactory(LdapTemplateFactory templateFactory) {
        m_templateFactory = templateFactory;
    }
}