001/* 002 * Copyright 2018-2019 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2018-2019 Ping Identity Corporation 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License (GPLv2 only) 010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 011 * as published by the Free Software Foundation. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Public License for more details. 017 * 018 * You should have received a copy of the GNU General Public License 019 * along with this program; if not, see <http://www.gnu.org/licenses>. 020 */ 021package com.unboundid.ldap.sdk; 022 023 024 025import com.unboundid.util.Debug; 026import com.unboundid.util.ThreadSafety; 027import com.unboundid.util.ThreadSafetyLevel; 028 029 030 031/** 032 * This class provides an implementation of a referral connector that will 033 * retain the exception encountered on the last attempt to establish a 034 * connection for the purpose of following a referral. 035 * <BR><BR> 036 * Note that although this class is technically safe to be used concurrently by 037 * multiple threads in that it won't result in a deadlock or concurrent 038 * modification exception or any other kind of obvious failure, it only retains 039 * a single exception, and only from the last attempt made to establish a 040 * connection for the purpose of following a referral. If multiple threads try 041 * to use the same instance of this connector concurrently, a call to the 042 * {@link #getExceptionFromLastConnectAttempt()} method may return the result 043 * from the last attempt made on another thread. It is therefore recommended 044 * that this connector only be used in contexts where it can be safely assumed 045 * that it will not be used concurrently across multiple threads. For example, 046 * if a connection is not expected to be concurrently shared by multiple 047 * threads, then it may be desirable to use the 048 * {@link LDAPConnection#setReferralConnector(ReferralConnector)} to set a 049 * different instance of this connector for each connection. Alternately, the 050 * {@link LDAPRequest#setReferralConnector(ReferralConnector)} method may be 051 * used to specify a connector that should be used for an individual request. 052 */ 053@ThreadSafety(level=ThreadSafetyLevel.MOSTLY_NOT_THREADSAFE) 054public final class RetainConnectExceptionReferralConnector 055 implements ReferralConnector 056{ 057 // The wrapped referral connector that will actually be used to establish the 058 // connection. 059 private final ReferralConnector wrappedReferralConnector; 060 061 // The exception caught in the last attempt to establish a connection for the 062 // purpose of following a referral. 063 private volatile LDAPException connectExceptionFromLastAttempt; 064 065 066 067 /** 068 * Creates a new instance of this referral connector that will use the 069 * connection's default referral handler to actually attempt to establish a 070 * connection. 071 */ 072 public RetainConnectExceptionReferralConnector() 073 { 074 this(null); 075 } 076 077 078 079 /** 080 * Creates a new instance of this referral connector that will use the 081 * provided connector to actually attempt to establish a connection. 082 * 083 * @param wrappedReferralConnector The referral connector that will be used 084 * to actually attempt to establish a 085 * connection for the purpose of following a 086 * referral. This may be {@code null} to 087 * use the default referral connector for 088 * the connection on which the referral was 089 * received. 090 */ 091 public RetainConnectExceptionReferralConnector( 092 final ReferralConnector wrappedReferralConnector) 093 { 094 this.wrappedReferralConnector = wrappedReferralConnector; 095 096 connectExceptionFromLastAttempt = null; 097 } 098 099 100 101 /** 102 * Retrieves the exception that was caught in the last attempt to establish a 103 * connection for the purpose of following a referral, if any. 104 * 105 * @return The exception that was caught in the last attempt to establish a 106 * connection for the purpose of following a referral, or 107 * {@code null} if the last connection attempt was successful or if 108 * there have not yet been any connection attempts. 109 */ 110 public LDAPException getExceptionFromLastConnectAttempt() 111 { 112 return connectExceptionFromLastAttempt; 113 } 114 115 116 117 /** 118 * {@inheritDoc} 119 */ 120 @Override() 121 public LDAPConnection getReferralConnection(final LDAPURL referralURL, 122 final LDAPConnection connection) 123 throws LDAPException 124 { 125 final ReferralConnector connector; 126 if (wrappedReferralConnector == null) 127 { 128 connector = connection.getReferralConnector(); 129 } 130 else 131 { 132 connector = wrappedReferralConnector; 133 } 134 135 LDAPException connectException = null; 136 try 137 { 138 return connector.getReferralConnection(referralURL, connection); 139 } 140 catch (final LDAPException e) 141 { 142 Debug.debugException(e); 143 connectException = e; 144 throw e; 145 } 146 finally 147 { 148 connectExceptionFromLastAttempt = connectException; 149 } 150 } 151}