From f4adb673cc6d7bf9945e0118cb49b647418bc184 Mon Sep 17 00:00:00 2001 From: Szymon Sasin Date: Tue, 13 Aug 2024 08:29:45 +0300 Subject: [PATCH] GH-82 TransportContext: merge and key iterator (#85) * GH-82 TransportContext: merge and key iterator --- .../com/mbed/coap/packet/CoapRequest.java | 5 ++ .../mbed/coap/transport/TransportContext.java | 45 +++++++++------ .../com/mbed/coap/packet/CoapRequestTest.java | 5 +- .../coap/transport/TransportContextTest.java | 57 ++++++++++++++++++- 4 files changed, 90 insertions(+), 22 deletions(-) diff --git a/coap-core/src/main/java/com/mbed/coap/packet/CoapRequest.java b/coap-core/src/main/java/com/mbed/coap/packet/CoapRequest.java index 35411d1e..847ae841 100644 --- a/coap-core/src/main/java/com/mbed/coap/packet/CoapRequest.java +++ b/coap-core/src/main/java/com/mbed/coap/packet/CoapRequest.java @@ -279,6 +279,11 @@ public Builder addContext(TransportContext.Key key, T value) { return this; } + public Builder addContext(TransportContext context) { + transContext = transContext.with(context); + return this; + } + public Builder address(InetSocketAddress address) { this.peerAddress = address; return this; diff --git a/coap-core/src/main/java/com/mbed/coap/transport/TransportContext.java b/coap-core/src/main/java/com/mbed/coap/transport/TransportContext.java index 103dc1c5..f01e18b7 100644 --- a/coap-core/src/main/java/com/mbed/coap/transport/TransportContext.java +++ b/coap-core/src/main/java/com/mbed/coap/transport/TransportContext.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 java-coap contributors (https://github.com/open-coap/java-coap) + * Copyright (C) 2022-2024 java-coap contributors (https://github.com/open-coap/java-coap) * SPDX-License-Identifier: Apache-2.0 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,9 @@ import static java.util.Objects.requireNonNull; import java.time.Duration; +import java.util.HashSet; import java.util.Objects; +import java.util.Set; public final class TransportContext { @@ -66,6 +68,17 @@ public TransportContext with(Key key, T value) { return new TransportContext(requireNonNull(key), requireNonNull(value), this); } + public TransportContext with(TransportContext otherCtx) { + if (otherCtx.equals(EMPTY)) { + return this; + } + TransportContext mergedContext = this.with(otherCtx.key, otherCtx.value); + if (otherCtx.next == null) { + return mergedContext; + } + return mergedContext.with(otherCtx.next); + } + @Override public boolean equals(Object o) { if (this == o) { @@ -83,28 +96,24 @@ public int hashCode() { return Objects.hash(key, value, next); } + public Set> keys() { + Set> keys = new HashSet<>(); + addKey(keys); + return keys; + } + + private void addKey(Set> keys) { + keys.add(key); + if (next != null) { + next.addKey(keys); + } + } + public static final class Key { private final T defaultValue; public Key(T defaultValue) { this.defaultValue = defaultValue; } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Key key = (Key) o; - return Objects.equals(defaultValue, key.defaultValue); - } - - @Override - public int hashCode() { - return Objects.hash(defaultValue); - } } } diff --git a/coap-core/src/test/java/com/mbed/coap/packet/CoapRequestTest.java b/coap-core/src/test/java/com/mbed/coap/packet/CoapRequestTest.java index 73f96367..69096287 100644 --- a/coap-core/src/test/java/com/mbed/coap/packet/CoapRequestTest.java +++ b/coap-core/src/test/java/com/mbed/coap/packet/CoapRequestTest.java @@ -26,6 +26,7 @@ import static com.mbed.coap.packet.MediaTypes.CT_APPLICATION_JSON; import static com.mbed.coap.packet.Opaque.EMPTY; import static com.mbed.coap.packet.Opaque.decodeHex; +import static com.mbed.coap.transport.TransportContext.NON_CONFIRMABLE; import static com.mbed.coap.transport.TransportContext.RESPONSE_TIMEOUT; import static java.time.Duration.ofSeconds; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -96,11 +97,13 @@ void shouldModifyTransportContext() { // when CoapRequest request2 = request.modify() - .addContext(DUMMY_KEY, "test") + .addContext(NON_CONFIRMABLE, true) + .addContext(TransportContext.of(DUMMY_KEY, "test")) .build(); // then assertEquals("test", request2.getTransContext(DUMMY_KEY)); + assertEquals(true, request2.getTransContext(NON_CONFIRMABLE)); } @Test diff --git a/coap-core/src/test/java/com/mbed/coap/transport/TransportContextTest.java b/coap-core/src/test/java/com/mbed/coap/transport/TransportContextTest.java index d57d3de8..445be53a 100644 --- a/coap-core/src/test/java/com/mbed/coap/transport/TransportContextTest.java +++ b/coap-core/src/test/java/com/mbed/coap/transport/TransportContextTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 java-coap contributors (https://github.com/open-coap/java-coap) + * Copyright (C) 2022-2024 java-coap contributors (https://github.com/open-coap/java-coap) * SPDX-License-Identifier: Apache-2.0 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,7 +15,10 @@ */ package com.mbed.coap.transport; +import static com.mbed.coap.transport.TransportContext.EMPTY; +import static org.assertj.core.util.Sets.set; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNull; import nl.jqno.equalsverifier.EqualsVerifier; import nl.jqno.equalsverifier.Warning; @@ -26,6 +29,7 @@ public class TransportContextTest { private TransportContext.Key DUMMY_KEY = new TransportContext.Key<>(null); private TransportContext.Key DUMMY_KEY2 = new TransportContext.Key<>("na"); + private TransportContext.Key DUMMY_KEY3 = new TransportContext.Key<>(null); @Test void test() { @@ -38,12 +42,49 @@ void test() { assertEquals("afds", trans.get(DUMMY_KEY2)); } + @Test + void merge() { + TransportContext ctx1 = TransportContext.of(DUMMY_KEY, "111"); + TransportContext ctx2 = TransportContext.of(DUMMY_KEY2, "222"); + + TransportContext ctx3 = ctx1.with(ctx2); + + assertEquals("111", ctx3.get(DUMMY_KEY)); + assertEquals("222", ctx3.get(DUMMY_KEY2)); + assertEquals(set(DUMMY_KEY, DUMMY_KEY2), ctx3.keys()); + } + + @Test + void mergeWithEmpty() { + TransportContext ctx1 = TransportContext.of(DUMMY_KEY, "111"); + + assertEquals(ctx1, ctx1.with(EMPTY)); + assertEquals(ctx1, EMPTY.with(ctx1)); + assertEquals(set(DUMMY_KEY), ctx1.keys()); + } + + @Test + void mergeAndOverWrite() { + TransportContext ctx1 = TransportContext.of(DUMMY_KEY, "111").with(DUMMY_KEY2, "222"); + TransportContext ctx2 = TransportContext.of(DUMMY_KEY, "aaa").with(DUMMY_KEY3, "333"); + + TransportContext ctx3 = ctx1.with(ctx2); + + assertEquals("aaa", ctx3.get(DUMMY_KEY)); + assertEquals("222", ctx3.get(DUMMY_KEY2)); + assertEquals("333", ctx3.get(DUMMY_KEY3)); + + assertEquals(set(DUMMY_KEY, DUMMY_KEY2, DUMMY_KEY3), ctx3.keys()); + } + @Test void empty() { - TransportContext trans = TransportContext.EMPTY; + TransportContext trans = EMPTY; assertNull(trans.get(DUMMY_KEY)); assertEquals("default-val", trans.getOrDefault(DUMMY_KEY2, "default-val")); assertEquals("na", trans.get(DUMMY_KEY2)); + + assertEquals(EMPTY, EMPTY.with(EMPTY)); } @Test @@ -51,8 +92,18 @@ public void equalsAndHashTest() throws Exception { EqualsVerifier.forClass(TransportContext.class) .suppress(Warning.NONFINAL_FIELDS) .usingGetClass() - .withPrefabValues(TransportContext.class, TransportContext.EMPTY, TransportContext.of(TransportContext.NON_CONFIRMABLE, true)) + .withPrefabValues(TransportContext.class, EMPTY, TransportContext.of(TransportContext.NON_CONFIRMABLE, true)) .verify(); } + @Test + public void equalsAndHashKeys() { + assertEquals(DUMMY_KEY, DUMMY_KEY); + + assertNotEquals(DUMMY_KEY, DUMMY_KEY2); + assertNotEquals(DUMMY_KEY, DUMMY_KEY3); + + assertNotEquals(new TransportContext.Key(null), new TransportContext.Key(null)); + } + }