From 99bd43ed5163bf635ef4c9f1db2d93d7f0232382 Mon Sep 17 00:00:00 2001 From: Norman Maurer Date: Mon, 9 Feb 2015 09:41:56 +0100 Subject: [PATCH] Allow to get existing ChannelOption / AttributeKey from String Motivation: We should allow to get a ChannelOption/AttributeKey from a String. This will make it a lot easier to make use of configuration files in applications. Modifications: - Add exists(...), newInstance(...) method to ChannelOption and AttributeKey and alter valueOf(...) to return an existing instance for a String or create one. - Add unit tests. Result: Much more flexible usage of ChannelOption and AttributeKey. --- .../main/java/io/netty/util/AttributeKey.java | 15 ++++- .../main/java/io/netty/util/ConstantPool.java | 39 +++++++++++ .../java/io/netty/util/AttributeKeyTest.java | 59 +++++++++++++++++ .../java/io/netty/channel/ChannelOption.java | 16 +++++ .../io/netty/channel/ChannelOptionTest.java | 64 +++++++++++++++++++ 5 files changed, 192 insertions(+), 1 deletion(-) create mode 100644 common/src/test/java/io/netty/util/AttributeKeyTest.java create mode 100644 transport/src/test/java/io/netty/channel/ChannelOptionTest.java diff --git a/common/src/main/java/io/netty/util/AttributeKey.java b/common/src/main/java/io/netty/util/AttributeKey.java index 4d52b94207..cafc92c816 100644 --- a/common/src/main/java/io/netty/util/AttributeKey.java +++ b/common/src/main/java/io/netty/util/AttributeKey.java @@ -40,8 +40,21 @@ public final class AttributeKey extends AbstractConstant> { } /** - * Shortcut of {@link #valueOf(String) valueOf(firstNameComponent.getName() + "#" + secondNameComponent)}. + * Returns {@code true} if a {@link AttributeKey} exists for the given {@code name}. */ + public static boolean exists(String name) { + return pool.exists(name); + } + + /** + * Creates a new {@link AttributeKey} for the given {@param name} or fail with an + * {@link IllegalArgumentException} if a {@link AttributeKey} for the given {@param name} exists. + */ + @SuppressWarnings("unchecked") + public static AttributeKey newInstance(String name) { + return (AttributeKey) pool.newInstance(name); + } + @SuppressWarnings("unchecked") public static AttributeKey valueOf(Class firstNameComponent, String secondNameComponent) { return (AttributeKey) pool.valueOf(firstNameComponent, secondNameComponent); diff --git a/common/src/main/java/io/netty/util/ConstantPool.java b/common/src/main/java/io/netty/util/ConstantPool.java index 13601e59e8..1a9945f5ef 100644 --- a/common/src/main/java/io/netty/util/ConstantPool.java +++ b/common/src/main/java/io/netty/util/ConstantPool.java @@ -16,6 +16,8 @@ package io.netty.util; +import io.netty.util.internal.ObjectUtil; + import java.util.HashMap; import java.util.Map; @@ -73,5 +75,42 @@ public abstract class ConstantPool> { } } + /** + * Returns {@code true} if a {@link AttributeKey} exists for the given {@code name}. + */ + public boolean exists(String name) { + ObjectUtil.checkNotNull(name, "name"); + synchronized (constants) { + return constants.containsKey(name); + } + } + + /** + * Creates a new {@link Constant} for the given {@param name} or fail with an + * {@link IllegalArgumentException} if a {@link Constant} for the given {@param name} exists. + */ + @SuppressWarnings("unchecked") + public T newInstance(String name) { + if (name == null) { + throw new NullPointerException("name"); + } + + if (name.isEmpty()) { + throw new IllegalArgumentException("empty name"); + } + + synchronized (constants) { + T c = constants.get(name); + if (c == null) { + c = newConstant(nextId, name); + constants.put(name, c); + nextId ++; + } else { + throw new IllegalArgumentException(String.format("'%s' is already in use", name)); + } + return c; + } + } + protected abstract T newConstant(int id, String name); } diff --git a/common/src/test/java/io/netty/util/AttributeKeyTest.java b/common/src/test/java/io/netty/util/AttributeKeyTest.java new file mode 100644 index 0000000000..ebaa3adbc3 --- /dev/null +++ b/common/src/test/java/io/netty/util/AttributeKeyTest.java @@ -0,0 +1,59 @@ +/* + * Copyright 2015 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.util; + +import org.junit.Test; + +import static org.junit.Assert.*; + +public class AttributeKeyTest { + + @Test + public void testExists() { + String name = "test"; + assertFalse(AttributeKey.exists(name)); + AttributeKey attr = AttributeKey.valueOf(name); + + assertTrue(AttributeKey.exists(name)); + assertNotNull(attr); + } + + @Test + public void testValueOf() { + String name = "test1"; + assertFalse(AttributeKey.exists(name)); + AttributeKey attr = AttributeKey.valueOf(name); + AttributeKey attr2 = AttributeKey.valueOf(name); + + assertSame(attr, attr2); + } + + @Test + public void testNewInstance() { + String name = "test2"; + assertFalse(AttributeKey.exists(name)); + AttributeKey attr = AttributeKey.newInstance(name); + assertTrue(AttributeKey.exists(name)); + assertNotNull(attr); + + try { + AttributeKey.newInstance(name); + fail(); + } catch (IllegalArgumentException e) { + // expected + } + } +} diff --git a/transport/src/main/java/io/netty/channel/ChannelOption.java b/transport/src/main/java/io/netty/channel/ChannelOption.java index acd4423051..74c623f1eb 100644 --- a/transport/src/main/java/io/netty/channel/ChannelOption.java +++ b/transport/src/main/java/io/netty/channel/ChannelOption.java @@ -55,6 +55,22 @@ public final class ChannelOption extends AbstractConstant> { return (ChannelOption) pool.valueOf(firstNameComponent, secondNameComponent); } + /** + * Returns {@code true} if a {@link ChannelOption} exists for the given {@code name}. + */ + public static boolean exists(String name) { + return pool.exists(name); + } + + /** + * Creates a new {@link ChannelOption} for the given {@param name} or fail with an + * {@link IllegalArgumentException} if a {@link ChannelOption} for the given {@param name} exists. + */ + @SuppressWarnings("unchecked") + public static ChannelOption newInstance(String name) { + return (ChannelOption) pool.newInstance(name); + } + public static final ChannelOption ALLOCATOR = valueOf("ALLOCATOR"); public static final ChannelOption RCVBUF_ALLOCATOR = valueOf("RCVBUF_ALLOCATOR"); public static final ChannelOption MESSAGE_SIZE_ESTIMATOR = valueOf("MESSAGE_SIZE_ESTIMATOR"); diff --git a/transport/src/test/java/io/netty/channel/ChannelOptionTest.java b/transport/src/test/java/io/netty/channel/ChannelOptionTest.java new file mode 100644 index 0000000000..24542bf5f0 --- /dev/null +++ b/transport/src/test/java/io/netty/channel/ChannelOptionTest.java @@ -0,0 +1,64 @@ +/* + * Copyright 2015 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.channel; + +import org.junit.Test; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + + +public class ChannelOptionTest { + + @Test + public void testExists() { + String name = "test"; + assertFalse(ChannelOption.exists(name)); + ChannelOption option = ChannelOption.valueOf(name); + + assertTrue(ChannelOption.exists(name)); + assertNotNull(option); + } + + @Test + public void testValueOf() { + String name = "test1"; + assertFalse(ChannelOption.exists(name)); + ChannelOption option = ChannelOption.valueOf(name); + ChannelOption option2 = ChannelOption.valueOf(name); + + assertSame(option, option2); + } + + @Test + public void testCreateOrFail() { + String name = "test2"; + assertFalse(ChannelOption.exists(name)); + ChannelOption option = ChannelOption.newInstance(name); + assertTrue(ChannelOption.exists(name)); + assertNotNull(option); + + try { + ChannelOption.newInstance(name); + fail(); + } catch (IllegalArgumentException e) { + // expected + } + } +}