Skip to content

Add Connection#openChannel to return Optional<Channel> #433

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions src/main/java/com/rabbitmq/client/Connection.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.io.IOException;
import java.net.InetAddress;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ExecutorService;

/**
Expand Down Expand Up @@ -117,6 +118,9 @@ public interface Connection extends ShutdownNotifier, Closeable { // rename to A
* Create a new channel, using an internally allocated channel number.
* If <a href="http://www.rabbitmq.com/api-guide.html#recovery">automatic connection recovery</a>
* is enabled, the channel returned by this method will be {@link Recoverable}.
* <p>
* Use {@link #openChannel()} if you want to use an {@link Optional} to deal
* with a {@null} value.
*
* @return a new channel descriptor, or null if none is available
* @throws IOException if an I/O problem is encountered
Expand All @@ -125,12 +129,51 @@ public interface Connection extends ShutdownNotifier, Closeable { // rename to A

/**
* Create a new channel, using the specified channel number if possible.
* <p>
* Use {@link #openChannel(int)} if you want to use an {@link Optional} to deal
* with a {@null} value.
*
* @param channelNumber the channel number to allocate
* @return a new channel descriptor, or null if this channel number is already in use
* @throws IOException if an I/O problem is encountered
*/
Channel createChannel(int channelNumber) throws IOException;

/**
* Create a new channel wrapped in an {@link Optional}.
* The channel number is allocated internally.
* <p>
* If <a href="http://www.rabbitmq.com/api-guide.html#recovery">automatic connection recovery</a>
* is enabled, the channel returned by this method will be {@link Recoverable}.
* <p>
* Use {@link #createChannel()} to return directly a {@link Channel} or {@code null}.
*
* @return an {@link Optional} containing the channel;
* never {@code null} but potentially empty if no channel is available
* @throws IOException if an I/O problem is encountered
* @see #createChannel()
* @since 5.6.0
*/
default Optional<Channel> openChannel() throws IOException {
return Optional.ofNullable(createChannel());
}

/**
* Create a new channel, using the specified channel number if possible.
* <p>
* Use {@link #createChannel(int)} to return directly a {@link Channel} or {@code null}.
*
* @param channelNumber the channel number to allocate
* @return an {@link Optional} containing the channel,
* never {@code null} but potentially empty if this channel number is already in use
* @throws IOException if an I/O problem is encountered
* @see #createChannel(int)
* @since 5.6.0
*/
default Optional<Channel> openChannel(int channelNumber) throws IOException {
return Optional.ofNullable(createChannel(channelNumber));
}

/**
* Close this connection and all its channels
* with the {@link com.rabbitmq.client.AMQP#REPLY_SUCCESS} close code
Expand Down
3 changes: 2 additions & 1 deletion src/test/java/com/rabbitmq/client/test/ClientTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@
DefaultRetryHandlerTest.class,
NioDeadlockOnConnectionClosing.class,
GeneratedClassesTest.class,
RpcTopologyRecordingTest.class
RpcTopologyRecordingTest.class,
ConnectionTest.class
})
public class ClientTests {

Expand Down
127 changes: 127 additions & 0 deletions src/test/java/com/rabbitmq/client/test/ConnectionTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved.
//
// This software, the RabbitMQ Java client library, is triple-licensed under the
// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2
// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see
// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL,
// please see LICENSE-APACHE2.
//
// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND,
// either express or implied. See the LICENSE file for specific language governing
// rights and limitations of this software.
//
// If you have any questions regarding licensing, please contact us at
// [email protected].

package com.rabbitmq.client.test;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.mockito.Mock;
import org.mockito.stubbing.OngoingStubbing;

import java.io.IOException;
import java.util.NoSuchElementException;
import java.util.Optional;

import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;

@RunWith(Parameterized.class)
public class ConnectionTest {

@Parameterized.Parameter
public TestConfigurator configurator;
@Mock
Connection c = mock(Connection.class);
@Mock
Channel ch = mock(Channel.class);

@Parameterized.Parameters
public static Object[] configurators() {
return new Object[]{new NotNumberedChannelCreationCallback(), new NumberedChannelCreationCallback()};
}

@Before
public void init() {
initMocks(this);
}

@Test
public void openChannelWithNonNullChannelShouldReturnNonEmptyOptional() throws Exception {
configurator.mockAndWhenChannel(c).thenReturn(ch);
configurator.mockAndWhenOptional(c).thenCallRealMethod();
Optional<Channel> optional = configurator.open(c);
assertTrue(optional.isPresent());
assertSame(ch, optional.get());
}

@Test(expected = NoSuchElementException.class)
public void openChannelWithNullChannelShouldReturnEmptyOptional() throws Exception {
configurator.mockAndWhenChannel(c).thenReturn(null);
configurator.mockAndWhenOptional(c).thenCallRealMethod();
Optional<Channel> optional = configurator.open(c);
assertFalse(optional.isPresent());
optional.get();
}

@Test(expected = IOException.class)
public void openChannelShouldPropagateIoException() throws Exception {
configurator.mockAndWhenChannel(c).thenThrow(IOException.class);
configurator.mockAndWhenOptional(c).thenCallRealMethod();
configurator.open(c);
}

interface TestConfigurator {

OngoingStubbing<Channel> mockAndWhenChannel(Connection c) throws IOException;

OngoingStubbing<Optional<Channel>> mockAndWhenOptional(Connection c) throws IOException;

Optional<Channel> open(Connection c) throws IOException;

}

static class NotNumberedChannelCreationCallback implements TestConfigurator {

@Override
public OngoingStubbing<Channel> mockAndWhenChannel(Connection c) throws IOException {
return when(c.createChannel());
}

@Override
public OngoingStubbing<Optional<Channel>> mockAndWhenOptional(Connection c) throws IOException {
return when(c.openChannel());
}

@Override
public Optional<Channel> open(Connection c) throws IOException {
return c.openChannel();
}
}

static class NumberedChannelCreationCallback implements TestConfigurator {

@Override
public OngoingStubbing<Channel> mockAndWhenChannel(Connection c) throws IOException {
return when(c.createChannel(1));
}

@Override
public OngoingStubbing<Optional<Channel>> mockAndWhenOptional(Connection c) throws IOException {
return when(c.openChannel(1));
}

@Override
public Optional<Channel> open(Connection c) throws IOException {
return c.openChannel(1);
}
}

}