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 * https://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 */ 020 021package org.apache.directory.ldap.client.api; 022 023 024import org.apache.commons.pool2.PooledObject; 025import org.apache.commons.pool2.impl.DefaultPooledObject; 026import org.apache.directory.api.asn1.util.Oid; 027import org.apache.directory.api.i18n.I18n; 028import org.apache.directory.api.ldap.model.exception.LdapException; 029import org.apache.directory.api.ldap.model.message.BindRequest; 030import org.apache.directory.api.ldap.model.message.ExtendedRequest; 031import org.apache.directory.api.ldap.model.name.Dn; 032import org.slf4j.Logger; 033import org.slf4j.LoggerFactory; 034 035 036/** 037 * A factory for creating LdapConnection objects managed by LdapConnectionPool. 038 * A bind operation is executed upon return if any of the following operations 039 * were performed on the connection while it was checked out: 040 * 041 * <ul> 042 * <li>{@link LdapConnection#bind() bind()}</li> 043 * <li>{@link LdapConnection#anonymousBind() anonymousBind()}</li> 044 * <li>{@link LdapConnection#bind(String) bind(String)}</li> 045 * <li>{@link LdapConnection#bind(String, String) bind(String, String)}</li> 046 * <li>{@link LdapConnection#bind(Dn) bind(Dn)}</li> 047 * <li>{@link LdapConnection#bind(Dn, String) bind(Dn, String)}</li> 048 * <li>{@link LdapConnection#bind(BindRequest) bind(BindRequest)}</li> 049 * <li>{@link LdapConnection#extended(String) extended(String)} <i>where oid is StartTLS</i></li> 050 * <li>{@link LdapConnection#extended(String, byte[]) extended(String, byte[])} <i>where oid is StartTLS</i></li> 051 * <li>{@link LdapConnection#extended(Oid) extended(String)} <i>where oid is StartTLS</i></li> 052 * <li>{@link LdapConnection#extended(Oid, byte[]) extended(String, byte[])} <i>where oid is StartTLS</i></li> 053 * <li>{@link LdapConnection#extended(ExtendedRequest) extended(ExtendedRequest)} <i>where ExtendedRequest is StartTLS</i></li> 054 * </ul> 055 * 056 * This is a <i>MOSTLY</i> safe way to handle connections in a pool. If one 057 * would like to use a slightly less expensive pool factory, the 058 * {@link DefaultPoolableLdapConnectionFactory} may be the right choice. 059 * 060 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 061 */ 062public class ValidatingPoolableLdapConnectionFactory extends AbstractPoolableLdapConnectionFactory 063{ 064 /** This class logger */ 065 private static final Logger LOG = LoggerFactory.getLogger( ValidatingPoolableLdapConnectionFactory.class ); 066 067 068 /** 069 * Creates a new instance of ValidatingPoolableLdapConnectionFactory. 070 * 071 * @param config the configuration for creating LdapConnections 072 */ 073 public ValidatingPoolableLdapConnectionFactory( LdapConnectionConfig config ) 074 { 075 this( new DefaultLdapConnectionFactory( config ) ); 076 } 077 078 079 /** 080 * Creates a new instance of ValidatingPoolableLdapConnectionFactory. The 081 * <code>connectionFactoryClass</code> must have a public constructor accepting 082 * an <code>LdapConnectionConfig</code> object or an 083 * <code>IllegalArgumentException</code> will be thrown. 084 * 085 * @param config the configuration for creating LdapConnections 086 * @param connectionFactoryClass An implementation class of for the 087 * LDAP connection factory. 088 * @throws IllegalArgumentException If the instantiation of an instance of 089 * the <code>connectionFactoryClass</code> fails. 090 */ 091 public ValidatingPoolableLdapConnectionFactory( LdapConnectionConfig config, 092 Class<? extends LdapConnectionFactory> connectionFactoryClass ) 093 { 094 this( newLdapConnectionFactory( config, connectionFactoryClass ) ); 095 } 096 097 098 /** 099 * Creates a new instance of ValidatingPoolableLdapConnectionFactory. 100 * 101 * @param connectionFactory the connection factory for creating LdapConnections 102 */ 103 public ValidatingPoolableLdapConnectionFactory( LdapConnectionFactory connectionFactory ) 104 { 105 this.connectionFactory = connectionFactory; 106 } 107 108 109 /** 110 * {@inheritDoc} 111 * 112 * There is nothing to do to activate a connection. 113 */ 114 @Override 115 public void activateObject( PooledObject<LdapConnection> pooledObject ) throws LdapException 116 { 117 LdapConnection connection = pooledObject.getObject(); 118 119 if ( LOG.isDebugEnabled() ) 120 { 121 LOG.debug( I18n.msg( I18n.MSG_04146_ACTIVATING, connection ) ); 122 } 123 124 super.activateObject( pooledObject ); 125 126 // clear the monitors 127 ( ( MonitoringLdapConnection ) connection ).resetMonitors(); 128 } 129 130 131 /** 132 * {@inheritDoc} 133 * 134 * Specifically, we are creating a new connection based on the LdapConnection Factory 135 * we used to create this pool of connections. The default is to create bound connections. 136 * 137 * @throws LdapException If unable to connect. 138 */ 139 @Override 140 public PooledObject<LdapConnection> makeObject() throws LdapException 141 { 142 if ( LOG.isDebugEnabled() ) 143 { 144 LOG.debug( I18n.msg( I18n.MSG_04150_CREATING_LDAP_CONNECTION ) ); 145 } 146 147 return new DefaultPooledObject<LdapConnection>( new MonitoringLdapConnection( connectionFactory.newLdapConnection() ) ); 148 } 149 150 151 /** 152 * {@inheritDoc} 153 * 154 * Here, passivating a connection means we re-bind it, so that the existing LDAPSession 155 * is reset. 156 * 157 * @throws LdapException If unable to reconfigure and rebind. 158 */ 159 @Override 160 public void passivateObject( PooledObject<LdapConnection> pooledObject ) throws LdapException 161 { 162 LdapConnection connection = pooledObject.getObject(); 163 164 if ( LOG.isDebugEnabled() ) 165 { 166 LOG.debug( I18n.msg( I18n.MSG_04151_PASSIVATING, connection ) ); 167 } 168 169 if ( !connection.isConnected() || !connection.isAuthenticated() 170 || ( ( MonitoringLdapConnection ) connection ).bindCalled() ) 171 { 172 if ( LOG.isDebugEnabled() ) 173 { 174 LOG.debug( I18n.msg( I18n.MSG_04172_REBIND_BIND_CONNECTION, connection ) ); 175 } 176 177 connectionFactory.bindConnection( connection ); 178 } 179 180 if ( ( ( MonitoringLdapConnection ) connection ).startTlsCalled() ) 181 { 182 if ( LOG.isDebugEnabled() ) 183 { 184 LOG.debug( I18n.msg( I18n.MSG_04173_UNBIND_START_TLS, connection ) ); 185 } 186 187 // unbind to clear the tls 188 connection.unBind(); 189 connectionFactory.bindConnection( connection ); 190 } 191 192 // in case connection had configuration changed 193 connectionFactory.configureConnection( connection ); 194 } 195}