From 583404868c92e881eb3470b148132dc035d86a3d Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Thu, 29 Aug 2013 21:01:42 +0000
Subject: [PATCH] Partial fix for OPENDJ-1112: LoadBalancing connection factories need better diagnostic messages
---
opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractLoadBalancingAlgorithm.java | 13 ++++++
opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/AbstractLoadBalancingAlgorithmTestCase.java | 98 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 110 insertions(+), 1 deletions(-)
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractLoadBalancingAlgorithm.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractLoadBalancingAlgorithm.java
index a868df4..2a4aaed 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractLoadBalancingAlgorithm.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractLoadBalancingAlgorithm.java
@@ -162,6 +162,9 @@
}
private void notifyOffline(final ErrorResultException error) {
+ // Save the error in case the load-balancer is exhausted.
+ lastFailure = error;
+
if (isOperational.getAndSet(false)) {
// Transition from online to offline.
if (DEBUG_LOG.isLoggable(Level.WARNING)) {
@@ -225,6 +228,14 @@
private final List<MonitoredConnectionFactory> monitoredFactories;
private final ReferenceCountedObject<ScheduledExecutorService>.Reference scheduler;
private final Object stateLock = new Object();
+
+ /**
+ * The last connection failure which caused a connection factory to be
+ * marked offline. This is used in order to help diagnose problems when the
+ * load-balancer has exhausted all of its factories.
+ */
+ private volatile ErrorResultException lastFailure = null;
+
/**
* Guarded by stateLock.
*/
@@ -335,6 +346,6 @@
* timeout period.
*/
throw newErrorResult(ResultCode.CLIENT_SIDE_CONNECT_ERROR,
- "No operational connection factories available");
+ "No operational connection factories available", lastFailure);
}
}
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/AbstractLoadBalancingAlgorithmTestCase.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/AbstractLoadBalancingAlgorithmTestCase.java
new file mode 100644
index 0000000..82aa5a2
--- /dev/null
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/AbstractLoadBalancingAlgorithmTestCase.java
@@ -0,0 +1,98 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at legal-notices/CDDLv1_0.txt.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Copyright 2013 ForgeRock AS
+ */
+package org.forgerock.opendj.ldap;
+
+import static java.util.Arrays.asList;
+import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.assertions.Fail.fail;
+import static org.forgerock.opendj.ldap.Connections.newLoadBalancer;
+import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.logging.Level;
+
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.forgerock.opendj.util.StaticUtils;
+
+@SuppressWarnings("javadoc")
+public class AbstractLoadBalancingAlgorithmTestCase extends SdkTestCase {
+
+ /**
+ * Disables logging before the tests.
+ */
+ @BeforeClass()
+ public void disableLogging() {
+ StaticUtils.DEBUG_LOG.setLevel(Level.SEVERE);
+ }
+
+ /**
+ * Re-enable logging after the tests.
+ */
+ @AfterClass()
+ public void enableLogging() {
+ StaticUtils.DEBUG_LOG.setLevel(Level.INFO);
+ }
+
+ /**
+ * Tests fix for OPENDJ-1112: when a load balancer fails completely the
+ * connection exception should include the last error that occurred.
+ */
+ @Test
+ public void testFinalFailureExposedAsCause() throws Exception {
+ /*
+ * Create load-balancer with two failed connection factories.
+ */
+ final ConnectionFactory first = mock(ConnectionFactory.class);
+ final ErrorResultException firstError = newErrorResult(ResultCode.CLIENT_SIDE_SERVER_DOWN);
+ when(first.getConnection()).thenThrow(firstError);
+
+ final ConnectionFactory second = mock(ConnectionFactory.class);
+ final ErrorResultException secondError = newErrorResult(ResultCode.CLIENT_SIDE_SERVER_DOWN);
+ when(second.getConnection()).thenThrow(secondError);
+
+ final ConnectionFactory loadBalancer =
+ newLoadBalancer(new RoundRobinLoadBalancingAlgorithm(asList(first, second)));
+
+ /*
+ * Belt and braces check to ensure that factory methods don't return
+ * same instance and fool this test.
+ */
+ assertThat(firstError).isNotSameAs(secondError);
+
+ try {
+ loadBalancer.getConnection().close();
+ fail("Unexpectedly obtained a connection");
+ } catch (ErrorResultException e) {
+ assertThat(e.getCause()).isSameAs(secondError);
+ } finally {
+ loadBalancer.close();
+ }
+ }
+}
--
Gitblit v1.10.0