<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:util="http://www.springframework.org/schema/util" xmlns="http://www.springframework.org/schema/beans"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/util
       http://www.springframework.org/schema/util/spring-util-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean id="springLdapPagedDao" class="com.armedia.acm.services.users.dao.ldap.SpringLdapPagedDao"/>

    <bean id="customPagedLdapDao" class="com.armedia.acm.services.users.dao.ldap.CustomPagedLdapDao"/>

    <bean id="springLdapUserDao" class="com.armedia.acm.services.users.dao.ldap.SpringLdapUserDao">
        <property name="ldapCrudDao" ref="ldapCrudDao"/>
        <property name="ldapEntryTransformer" ref="ldapEntryTransformer"/>
        <property name="passwordLengthValidationRule" ref="passwordLengthValidationRule"/>
    </bean>

    <bean id="springLdapGroupDao" class="com.armedia.acm.services.users.dao.ldap.SpringLdapGroupDao">
        <property name="ldapCrudDao" ref="ldapCrudDao"/>
        <property name="ldapEntryTransformer" ref="ldapEntryTransformer"/>
    </bean>

    <bean id="ldapCrudDao" class="com.armedia.acm.services.users.dao.ldap.LdapCrudDao">
        <property name="ldapDao" ref="customPagedLdapDao"/>
    </bean>

    <bean id="acmUserService" class="com.armedia.acm.services.users.service.AcmUserServiceImpl">
        <property name="userDao" ref="userJpaDao"/>
        <property name="executeSolrQuery" ref="executeSolrQuery"/>
        <property name="userRoleService" ref="userRoleService"/>
        <property name="rolesToPrivilegesConfig" ref="rolesToPrivileges"/>
    </bean>

    <bean id="userRoleService" class="com.armedia.acm.services.users.service.AcmUserRoleService">
        <property name="userDao" ref="userJpaDao"/>
        <property name="roleToGroupConfig" ref="acmRoleToGroupConfig"/>
    </bean>

    <bean id="userJpaDao" class="com.armedia.acm.services.users.dao.UserDao" init-method="init">
        <property name="languageSettingsConfig" ref="languageSettingsConfig"/>
    </bean>
    <!-- End UserDao caching functionality -->

    <bean id="userActionDao" class="com.armedia.acm.services.users.dao.UserActionDao"/>

    <bean id="groupDao" class="com.armedia.acm.services.users.dao.group.AcmGroupDao"/>

    <bean id="groupService" class="com.armedia.acm.services.users.service.group.GroupServiceImpl">
        <property name="userDao" ref="userJpaDao"/>
        <property name="groupDao" ref="groupDao"/>
        <property name="executeSolrQuery" ref="executeSolrQuery"/>
        <property name="acmGroupEventPublisher" ref="acmGroupEventPublisher"/>
        <property name="springContextHolder" ref="acmContextHolder"/>
    </bean>

    <bean id="userActionExecutor" class="com.armedia.acm.services.users.service.ldap.AcmUserActionExecutor">
        <property name="userActionDao" ref="userActionDao"/>
    </bean>

    <bean id="ldapSyncProcessor" class="com.armedia.acm.services.users.service.ldap.LdapSyncProcessor">
        <property name="groupDao" ref="groupDao"/>
        <property name="userDao" ref="userJpaDao"/>
        <property name="roleToGroupConfig" ref="acmRoleToGroupConfig"/>
        <property name="ldapDatabaseSyncService" ref="ldapDatabaseSyncService"/>
    </bean>

    <bean id="ldapDatabaseSyncService" class="com.armedia.acm.services.users.service.ldap.LdapDatabaseSyncService">
        <property name="userDao" ref="userJpaDao"/>
        <property name="groupDao" ref="groupDao"/>
        <property name="acmGroupEventPublisher" ref="acmGroupEventPublisher"/>
    </bean>

    <bean id="acmLdapAuthenticateManager" class="com.armedia.acm.services.users.service.ldap.LdapAuthenticateManager">
        <property name="springContextHolder" ref="acmContextHolder"/>
    </bean>

    <bean id="acmRoleToGroupConfig" class="com.armedia.acm.services.users.model.AcmRoleToGroupMapping">
        <property name="groupDao" ref="groupDao"/>
        <property name="rolesToGroupsConfig" ref="rolesToGroupsConfig"/>
    </bean>

    <!-- NOTE: LDAP sync service beans (of class com.armedia.acm.services.users.service.ldap.LdapSyncService) should
         be defined in dynamically-loaded Spring config files, placed in the ACM spring configuration folder
         ($HOME/.acm/spring). -->

    <!-- NOTE: LdapAuthenticateService beans (of class com.armedia.acm.services.users.service.ldap.LdapAuthenticateService) should
         be defined in dynamically-loaded Spring config files, placed in the ACM spring configuration folder
         ($HOME/.acm/spring). -->

    <bean id="userToSolrTransformer" class="com.armedia.acm.services.users.service.ldap.UserToSolrTransformer">
        <property name="userDao" ref="userJpaDao"/>
    </bean>

    <bean id="groupToSolrTransformer" class="com.armedia.acm.services.users.service.group.GroupToSolrTransformer">
        <property name="groupDao" ref="groupDao"/>
        <property name="userDao" ref="userJpaDao"/>
        <property name="springContextHolder" ref="acmContextHolder"/>
    </bean>

    <bean id="ldapUserService" class="com.armedia.acm.services.users.service.ldap.LdapUserService">
        <property name="ldapDao" ref="springLdapPagedDao"/>
        <property name="userDao" ref="userJpaDao"/>
        <property name="ldapUserDao" ref="springLdapUserDao"/>
        <property name="acmContextHolder" ref="acmContextHolder"/>
        <property name="ldapGroupDao" ref="springLdapGroupDao"/>
        <property name="groupService" ref="groupService"/>
    </bean>

    <bean id="ldapGroupService" class="com.armedia.acm.services.users.service.group.LdapGroupService">
        <property name="groupService" ref="groupService"/>
        <property name="userDao" ref="userJpaDao"/>
        <property name="acmContextHolder" ref="acmContextHolder"/>
        <property name="ldapEntryTransformer" ref="ldapEntryTransformer"/>
        <property name="ldapGroupDao" ref="springLdapGroupDao"/>
        <property name="acmGroupEventPublisher" ref="acmGroupEventPublisher"/>
    </bean>

    <bean id="ldapGroupNameValidator" class="com.armedia.acm.services.users.service.group.LdapGroupNameValidator"/>

    <bean id="ldapEntryTransformer" class="com.armedia.acm.services.users.service.ldap.LdapEntryTransformer">
        <property name="acmContextHolder" ref="acmContextHolder"/>
        <property name="ldapConfiguration" ref="acmSpringLdapConfig"/>
    </bean>

    <!-- password validation -->
    <bean id="passwordValidationService" class="com.armedia.acm.services.users.service.ldap.PasswordValidationService">
        <property name="passwordRules" ref="passwordValidation"/>
    </bean>

    <util:list id="passwordValidation" value-type="com.armedia.acm.services.users.model.ldap.PasswordValidationRule">
        <ref bean="passwordShouldNotContainUserId"/>
        <ref bean="passwordShouldMatchLowerCasePattern"/>
        <ref bean="passwordShouldMatchUpperCasePattern"/>
        <ref bean="passwordShouldMatchDigitPattern"/>
        <ref bean="passwordShouldMatchSpecialCharPattern"/>
        <ref bean="passwordLengthValidationRule"/>
    </util:list>

    <bean id="passwordShouldNotContainUserId"
        class="com.armedia.acm.services.users.model.ldap.PasswordShouldNotContainUserId"/>

    <bean id="passwordShouldMatchLowerCasePattern"
        class="com.armedia.acm.services.users.model.ldap.PasswordShouldMatchPattern">
        <constructor-arg type="java.lang.String" name="pattern" value="^.*?[a-z].*$"/>
        <constructor-arg type="java.lang.String" name="message"
            value="Password must contain at least one lowercase character"/>
    </bean>

    <bean id="passwordShouldMatchUpperCasePattern"
        class="com.armedia.acm.services.users.model.ldap.PasswordShouldMatchPattern">
        <constructor-arg type="java.lang.String" name="pattern" value="^.*?[A-Z].*$"/>
        <constructor-arg type="java.lang.String" name="message"
            value="Password must contain at least one uppercase character"/>
    </bean>

    <bean id="passwordShouldMatchDigitPattern"
        class="com.armedia.acm.services.users.model.ldap.PasswordShouldMatchPattern">
        <constructor-arg type="java.lang.String" name="pattern" value="^.*?[0-9].*$"/>
        <constructor-arg type="java.lang.String" name="message" value="Password must contain at least one digit (0-9)"/>
    </bean>

    <bean id="passwordShouldMatchSpecialCharPattern"
          class="com.armedia.acm.services.users.model.ldap.PasswordShouldMatchPattern">
        <constructor-arg type="java.lang.String" name="pattern">
            <value><![CDATA[^.*?[[~!@#$%^&*_+=`|\(){}:;"'<>,.?/-]].*$]]></value>
        </constructor-arg>
        <constructor-arg type="java.lang.String" name="message"
                         value="Password must contain at least one special character"/>
    </bean>

    <bean id="passwordLengthValidationRule" class="com.armedia.acm.services.users.model.ldap.PasswordLengthValidationRule">
        <property name="passwordConfig" ref="passwordConfig"/>
    </bean>
    <!-- end of password validation -->

    <bean id="passwordConfig" class="com.armedia.acm.services.users.model.PasswordConfig" scope="refresh">
        <aop:scoped-proxy/>
    </bean>

    <bean id="acmUserEventPublisher" class="com.armedia.acm.services.users.service.AcmUserEventPublisher"/>

    <bean id="acmGroupEventPublisher" class="com.armedia.acm.services.users.service.AcmGroupEventPublisher"/>

    <bean id="usersStateProvider" class="com.armedia.acm.services.users.state.AcmUsersStateProvider">
        <property name="userDao" ref="userJpaDao"/>
    </bean>

    <bean id="applicationPrivilegesConfig" class="com.armedia.acm.services.users.model.ApplicationPrivilegesConfig" scope="refresh">
        <aop:scoped-proxy/>
    </bean>

    <bean id="applicationRolesConfig" class="com.armedia.acm.services.users.model.ApplicationRolesConfig" scope="refresh">
        <aop:scoped-proxy/>
    </bean>

    <bean id="rolesToGroupsConfig" class="com.armedia.acm.services.users.model.ApplicationRolesToGroupsConfig" scope="refresh">
        <aop:scoped-proxy/>
    </bean>

    <bean id="rolesToPrivileges" class="com.armedia.acm.services.users.model.ApplicationRolesToPrivilegesConfig" scope="refresh">
        <aop:scoped-proxy/>
    </bean>

    <bean id="ldapContextChangedUpdateScheduler" class="com.armedia.acm.services.users.service.ldap.OnLdapContextChangedUpdateScheduler">
        <property name="schedulerService" ref="acmSchedulerService"/>
        <property name="contextHolder" ref="acmContextHolder"/>
        <property name="jobFactory" ref="acmJobFactory"/>
    </bean>

    <bean id="acmSpringLdapConfig" class="com.armedia.acm.services.users.service.ldap.AcmLdapConfiguration" scope="refresh">
        <aop:scoped-proxy/>
    </bean>

    <bean id="ldapSyncService" class="com.armedia.acm.services.users.service.ldap.LdapSyncService">
        <property name="ldapDao" ref="customPagedLdapDao"/>
        <property name="springLdapUserDao" ref="springLdapUserDao"/>
        <property name="auditPropertyEntityAdapter" ref="auditPropertyEntityAdapter"/>
        <property name="ldapSyncProcessor" ref="ldapSyncProcessor"/>
        <property name="schedulerService" ref="acmSchedulerService"/>
    </bean>

    <bean id="userAccessTokenDao"
          class="com.armedia.acm.services.users.dao.UserAccessTokenDao"/>

    <bean id="acmOAuth2AccessTokenService" class="com.armedia.acm.services.users.service.AcmOAuth2AccessTokenService">
        <property name="userAccessTokenDao" ref="userAccessTokenDao"/>
        <property name="clientRegistrationConfig" ref="oAuth2ClientRegistrationConfig"/>
        <property name="acmRestTemplate" ref="acmRestTemplate"/>
    </bean>

    <bean id="oAuth2ClientRegistrationConfig"
          class="com.armedia.acm.services.users.model.OAuth2ClientRegistrationConfig"/>

    <bean id="acmRestTemplate" class="org.springframework.web.client.RestTemplate"/>
</beans>