001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.directory.server.core.integ; 021 022import java.lang.reflect.AnnotatedElement; 023import java.lang.reflect.Constructor; 024import java.lang.reflect.Field; 025import java.lang.reflect.Method; 026 027import org.apache.commons.pool2.PooledObjectFactory; 028import org.apache.commons.pool2.impl.GenericObjectPoolConfig; 029import org.apache.directory.api.ldap.codec.api.DefaultConfigurableBinaryAttributeDetector; 030import org.apache.directory.api.util.Network; 031import org.apache.directory.ldap.client.api.LdapConnection; 032import org.apache.directory.ldap.client.api.LdapConnectionConfig; 033import org.apache.directory.ldap.client.api.LdapConnectionFactory; 034import org.apache.directory.ldap.client.api.LdapConnectionPool; 035import org.apache.directory.ldap.client.api.LdapConnectionValidator; 036import org.apache.directory.ldap.client.template.LdapConnectionTemplate; 037import org.apache.directory.server.annotations.CreateLdapConnectionPool; 038import org.apache.directory.server.ldap.LdapServer; 039import org.junit.jupiter.api.extension.AfterAllCallback; 040import org.junit.jupiter.api.extension.BeforeAllCallback; 041import org.junit.jupiter.api.extension.ExtensionContext; 042import org.slf4j.Logger; 043import org.slf4j.LoggerFactory; 044 045public class CreateLdapConnectionPoolExtension implements BeforeAllCallback, AfterAllCallback 046{ 047 private static final Logger LOG = LoggerFactory.getLogger( CreateLdapConnectionPoolExtension.class ); 048 private static final String LDAP_CONNECTION_TEMPLATE = "ldapConnectionTemplate"; 049 private static final String LDAP_CONNECTION_FACTORY = "ldapConnectionFactory"; 050 private static final String LDAP_CONNECTION_POOL = "ldapConnectionPool"; 051 052 private LdapConnectionFactory ldapConnectionFactory; 053 054 private void setLdapConnectionTemplate( ExtensionContext context, LdapConnectionTemplate ldapConnectionTemplate ) 055 throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException 056 { 057 Class<?> testClass = context.getTestClass().get(); 058 059 try 060 { 061 Field field = testClass.getField( LDAP_CONNECTION_TEMPLATE ); 062 field.set( null, ldapConnectionTemplate ); 063 } 064 catch ( NoSuchFieldException nsfe ) 065 { 066 // Ignore 067 } 068 } 069 070 071 private void setLdapConnectionPool( ExtensionContext context, LdapConnectionPool ldapConnectionPool ) 072 throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException 073 { 074 Class<?> testClass = context.getTestClass().get(); 075 076 try 077 { 078 Field field = testClass.getField( LDAP_CONNECTION_POOL ); 079 field.set( null, ldapConnectionPool ); 080 } 081 catch ( NoSuchFieldException nsfe ) 082 { 083 // Ignore 084 } 085 } 086 087 088 private void setLdapConnectionFactory( ExtensionContext context, LdapConnectionFactory ldapConnectionFactory ) 089 throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException 090 { 091 Class<?> testClass = context.getTestClass().get(); 092 093 try 094 { 095 Field field = testClass.getField( LDAP_CONNECTION_FACTORY ); 096 097 field.set( null, ldapConnectionFactory ); 098 } 099 catch ( NoSuchFieldException nsfe ) 100 { 101 // Ignore 102 } 103 } 104 105 106 private LdapServer getLdapServer( ExtensionContext context ) 107 throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException 108 { 109 Class<?> testClass = context.getTestClass().get(); 110 Field field = testClass.getField( ApacheDSTestExtension.CLASS_LS ); 111 112 if ( field != null ) 113 { 114 return ( LdapServer ) field.get( testClass ); 115 } 116 else 117 { 118 return null; 119 } 120 } 121 122 @Override 123 public void beforeAll( ExtensionContext context ) throws Exception 124 { 125 AnnotatedElement annotations = context.getTestClass().get(); 126 CreateLdapConnectionPool createLdapConnectionPool = annotations.getAnnotation( CreateLdapConnectionPool.class ); 127 128 LdapConnectionTemplate ldapConnectionTemplate; 129 LdapServer ldapServer = getLdapServer( context ); 130 131 if ( createLdapConnectionPool != null ) 132 { 133 LOG.trace( "Creating connection pool to new ldap server" ); 134 135 Class<? extends PooledObjectFactory<LdapConnection>> factoryClass = 136 createLdapConnectionPool.factoryClass(); 137 Class<? extends LdapConnectionFactory> connectionFactoryClass = 138 createLdapConnectionPool.connectionFactoryClass(); 139 Class<? extends LdapConnectionValidator> validatorClass = 140 createLdapConnectionPool.validatorClass(); 141 LdapConnectionPool ldapConnectionPool = createLdapConnectionPool( createLdapConnectionPool, ldapServer, factoryClass, 142 connectionFactoryClass, validatorClass ); 143 ldapConnectionTemplate = new LdapConnectionTemplate( ldapConnectionPool ); 144 145 setLdapConnectionTemplate( context, ldapConnectionTemplate ); 146 setLdapConnectionFactory( context, ldapConnectionFactory ); 147 setLdapConnectionPool( context, ldapConnectionPool ); 148 } 149 } 150 151 152 private LdapConnectionPool createLdapConnectionPool( 153 CreateLdapConnectionPool createLdapConnectionPool, 154 LdapServer ldapServer, 155 Class<? extends PooledObjectFactory<LdapConnection>> factoryClass, 156 Class<? extends LdapConnectionFactory> connectionFactoryClass, 157 Class<? extends LdapConnectionValidator> validatorClass ) 158 { 159 LdapConnectionConfig config = new LdapConnectionConfig(); 160 161 config.setLdapHost( Network.LOOPBACK_HOSTNAME ); 162 163 config.setLdapPort( ldapServer.getPort() ); 164 config.setName( "uid=admin,ou=system" ); 165 config.setCredentials( "secret" ); 166 167 if ( ( createLdapConnectionPool.additionalBinaryAttributes() != null ) 168 && ( createLdapConnectionPool.additionalBinaryAttributes().length > 0 ) ) 169 { 170 DefaultConfigurableBinaryAttributeDetector binaryAttributeDetector = 171 new DefaultConfigurableBinaryAttributeDetector(); 172 binaryAttributeDetector.addBinaryAttribute( 173 createLdapConnectionPool.additionalBinaryAttributes() ); 174 config.setBinaryAttributeDetector( binaryAttributeDetector ); 175 } 176 177 GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); 178 poolConfig.setLifo( createLdapConnectionPool.lifo() ); 179 poolConfig.setMaxTotal( createLdapConnectionPool.maxActive() ); 180 poolConfig.setMaxIdle( createLdapConnectionPool.maxIdle() ); 181 poolConfig.setMaxWaitMillis( createLdapConnectionPool.maxWait() ); 182 poolConfig.setMinEvictableIdleTimeMillis( createLdapConnectionPool 183 .minEvictableIdleTimeMillis() ); 184 poolConfig.setMinIdle( createLdapConnectionPool.minIdle() ); 185 poolConfig.setNumTestsPerEvictionRun( createLdapConnectionPool 186 .numTestsPerEvictionRun() ); 187 poolConfig.setSoftMinEvictableIdleTimeMillis( createLdapConnectionPool 188 .softMinEvictableIdleTimeMillis() ); 189 poolConfig.setTestOnBorrow( createLdapConnectionPool.testOnBorrow() ); 190 poolConfig.setTestOnReturn( createLdapConnectionPool.testOnReturn() ); 191 poolConfig.setTestWhileIdle( createLdapConnectionPool.testWhileIdle() ); 192 poolConfig.setTimeBetweenEvictionRunsMillis( createLdapConnectionPool 193 .timeBetweenEvictionRunsMillis() ); 194 poolConfig.setBlockWhenExhausted( createLdapConnectionPool 195 .whenExhaustedAction() == 1 ); 196 197 PooledObjectFactory<LdapConnection> poolableLdapConnectionFactory; 198 199 try 200 { 201 Constructor<? extends LdapConnectionFactory> constructor = 202 connectionFactoryClass.getConstructor( LdapConnectionConfig.class ); 203 ldapConnectionFactory = constructor.newInstance( config ); 204 } 205 catch ( Exception e ) 206 { 207 throw new IllegalArgumentException( "invalid connectionFactoryClass " 208 + connectionFactoryClass.getName() + ": " + e.getMessage(), e ); 209 } 210 try 211 { 212 Method timeoutSetter = connectionFactoryClass.getMethod( "setTimeOut", Long.TYPE ); 213 214 if ( timeoutSetter != null ) 215 { 216 timeoutSetter.invoke( ldapConnectionFactory, createLdapConnectionPool.timeout() ); 217 } 218 } 219 catch ( Exception e ) 220 { 221 throw new IllegalArgumentException( "invalid connectionFactoryClass " 222 + connectionFactoryClass.getName() + ", missing setTimeOut(long): " 223 + e.getMessage(), e ); 224 } 225 226 try 227 { 228 Constructor<? extends PooledObjectFactory<LdapConnection>> constructor = 229 factoryClass.getConstructor( LdapConnectionFactory.class ); 230 poolableLdapConnectionFactory = constructor.newInstance( ldapConnectionFactory ); 231 } 232 catch ( Exception e ) 233 { 234 throw new IllegalArgumentException( "invalid factoryClass " 235 + factoryClass.getName() + ": " + e.getMessage(), e ); 236 } 237 try 238 { 239 Method setValidator = factoryClass.getMethod( "setValidator", LdapConnectionValidator.class ); 240 241 if ( setValidator != null ) 242 { 243 setValidator.invoke( poolableLdapConnectionFactory, validatorClass.newInstance() ); 244 } 245 } 246 catch ( Exception e ) 247 { 248 throw new IllegalArgumentException( "invalid connectionFactoryClass " 249 + connectionFactoryClass.getName() + ", missing setTimeOut(long): " 250 + e.getMessage(), e ); 251 } 252 253 return new LdapConnectionPool( poolableLdapConnectionFactory, poolConfig ); 254 } 255 256 257 @Override 258 public void afterAll( ExtensionContext context ) throws Exception 259 { 260 // TODO Auto-generated method stub 261 262 } 263}