Skip to content

Commit

Permalink
#17 added some immutability tests.
Browse files Browse the repository at this point in the history
Signed-off-by: krj1imb <johannes.schneider@bosch-si.com>
  • Loading branch information
krj1imb committed Sep 26, 2019
1 parent 7631392 commit 1023c61
Show file tree
Hide file tree
Showing 16 changed files with 303 additions and 38 deletions.
4 changes: 2 additions & 2 deletions java/src/main/java/org/eclipse/ditto/client/DittoClients.java
Expand Up @@ -43,7 +43,7 @@ private DittoClients() {
* @param messagingProvider the messaging provider for this client.
* @return the client.
* @throws org.eclipse.ditto.client.authentication.AuthenticationException if authentication failed.
* @throws org.eclipse.ditto.client.messaging.ConnectException if a connection to the configured endpoint
* @throws org.eclipse.ditto.client.messaging.MessagingException if a connection to the configured endpoint
* could not be established
*/
public static DittoClient newInstance(final MessagingProvider messagingProvider) {
Expand All @@ -58,7 +58,7 @@ public static DittoClient newInstance(final MessagingProvider messagingProvider)
* @param liveMessagingProvider the messaging provider for the {@code Live} part of the client.
* @return the client.
* @throws org.eclipse.ditto.client.authentication.AuthenticationException if authentication failed.
* @throws org.eclipse.ditto.client.messaging.ConnectException if a connection to the configured endpoint
* @throws org.eclipse.ditto.client.messaging.MessagingException if a connection to the configured endpoint
* could not be established
*/
public static DittoClient newInstance(final MessagingProvider twinMessagingProvider,
Expand Down
Expand Up @@ -12,11 +12,14 @@
*/
package org.eclipse.ditto.client.authentication;

import javax.annotation.concurrent.Immutable;

/**
* This exception is thrown if an error occurred during authentication process of the Client.
*
* @since 1.0.0
*/
@Immutable
public class AuthenticationException extends RuntimeException {

private static final String DEFAULT_MESSAGE_TEMPLATE = "Authentication of session <%s> failed.";
Expand Down
Expand Up @@ -26,6 +26,8 @@
import java.util.Optional;
import java.util.function.Supplier;

import javax.annotation.concurrent.Immutable;

import org.eclipse.ditto.client.authentication.AuthenticationException;
import org.eclipse.ditto.client.configuration.internal.ClientCredentialsAuthenticationConfiguration;
import org.eclipse.ditto.json.JsonFactory;
Expand All @@ -39,6 +41,7 @@
*
* @since 1.0.0
*/
@Immutable
final class AccessTokenSupplier implements Supplier<JsonObject> {

private static final Logger LOGGER = LoggerFactory.getLogger(AccessTokenSupplier.class);
Expand Down
Expand Up @@ -20,6 +20,7 @@

import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import javax.annotation.concurrent.NotThreadSafe;

import org.eclipse.ditto.client.configuration.AuthenticationConfiguration;
import org.eclipse.ditto.client.configuration.ProxyConfiguration;
Expand All @@ -30,6 +31,7 @@
*
* @since 1.0.0
*/
@Immutable
public final class BasicAuthenticationConfiguration extends AbstractAuthenticationConfiguration {

private final String username;
Expand Down Expand Up @@ -98,7 +100,7 @@ public String toString() {
"]";
}

@Immutable
@NotThreadSafe
public static class BasicAuthenticationConfigurationBuilder implements AuthenticationConfiguration.Builder {

private String username;
Expand Down
Expand Up @@ -24,6 +24,7 @@

import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import javax.annotation.concurrent.NotThreadSafe;

import org.eclipse.ditto.client.configuration.AuthenticationConfiguration;
import org.eclipse.ditto.client.configuration.ProxyConfiguration;
Expand All @@ -34,6 +35,7 @@
*
* @since 1.0.0
*/
@Immutable
public final class ClientCredentialsAuthenticationConfiguration extends AbstractAuthenticationConfiguration {

private final String tokenEndpoint;
Expand Down Expand Up @@ -128,7 +130,7 @@ public String toString() {
"]";
}

@Immutable
@NotThreadSafe
public static class ClientCredentialsAuthenticationConfigurationBuilder
implements AuthenticationConfiguration.Builder {

Expand Down
Expand Up @@ -20,6 +20,7 @@

import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import javax.annotation.concurrent.NotThreadSafe;

import org.eclipse.ditto.client.configuration.AuthenticationConfiguration;
import org.eclipse.ditto.client.configuration.ProxyConfiguration;
Expand All @@ -30,6 +31,7 @@
*
* @since 1.0.0
*/
@Immutable
public final class DummyAuthenticationConfiguration extends AbstractAuthenticationConfiguration {

private final String dummyUsername;
Expand Down Expand Up @@ -84,7 +86,7 @@ public String toString() {
"]";
}

@Immutable
@NotThreadSafe
public static class DummyAuthenticationConfigurationBuilder implements AuthenticationConfiguration.Builder {

private String dummyUsername;
Expand Down
Expand Up @@ -52,7 +52,7 @@ private WebSocketMessagingConfiguration(final JsonSchemaVersion jsonSchemaVersio
}

public static MessagingConfiguration.Builder newBuilder() {
return new Builder();
return new WebSocketMessagingConfigurationBuilder();
}

@Override
Expand Down Expand Up @@ -80,7 +80,7 @@ public Optional<TrustStoreConfiguration> getTrustStoreConfiguration() {
return Optional.ofNullable(trustStoreConfiguration);
}

private static final class Builder implements MessagingConfiguration.Builder {
private static final class WebSocketMessagingConfigurationBuilder implements MessagingConfiguration.Builder {

private static final List<String> ALLOWED_URI_SCHEME = Arrays.asList("wss", "ws");
private static final String WS_PATH = "/ws/";
Expand Down
Expand Up @@ -12,12 +12,15 @@
*/
package org.eclipse.ditto.client.messaging;

import javax.annotation.concurrent.Immutable;

/**
* This exception is thrown if an error occurred during connection establishment.
* This exception is thrown if an error occurred within messaging.
*
* @since 1.0.0
*/
public class ConnectException extends RuntimeException {
@Immutable
public class MessagingException extends RuntimeException {

private static final String DEFAULT_MESSAGE_TEMPLATE = "Connect of session <%s> failed.";

Expand All @@ -29,20 +32,20 @@ public class ConnectException extends RuntimeException {

private static final long serialVersionUID = 6930767503633213674L;

private ConnectException(final String message, final Throwable cause) {
private MessagingException(final String message, final Throwable cause) {
super(message, cause);
}

public static ConnectException of(final String sessionId, final Throwable cause) {
return new ConnectException(String.format(DEFAULT_MESSAGE_TEMPLATE, sessionId), cause);
public static MessagingException connectFailed(final String sessionId, final Throwable cause) {
return new MessagingException(String.format(DEFAULT_MESSAGE_TEMPLATE, sessionId), cause);
}

public static ConnectException interrupted(final String sessionId, final Throwable cause) {
return new ConnectException(String.format(INTERRUPTED_MESSAGE_TEMPLATE, sessionId), cause);
public static MessagingException connectInterrupted(final String sessionId, final Throwable cause) {
return new MessagingException(String.format(INTERRUPTED_MESSAGE_TEMPLATE, sessionId), cause);
}

public static ConnectException timeout(final String sessionId, final Throwable cause) {
return new ConnectException(String.format(TIMEOUT_MESSAGE_TEMPLATE, sessionId), cause);
public static MessagingException connectTimeout(final String sessionId, final Throwable cause) {
return new MessagingException(String.format(TIMEOUT_MESSAGE_TEMPLATE, sessionId), cause);
}

}
Expand Up @@ -24,6 +24,7 @@
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
Expand All @@ -50,7 +51,7 @@
import org.eclipse.ditto.client.internal.DefaultThreadFactory;
import org.eclipse.ditto.client.internal.VersionReader;
import org.eclipse.ditto.client.live.internal.LiveImpl;
import org.eclipse.ditto.client.messaging.ConnectException;
import org.eclipse.ditto.client.messaging.MessagingException;
import org.eclipse.ditto.client.messaging.MessagingProvider;
import org.eclipse.ditto.client.twin.internal.TwinImpl;
import org.eclipse.ditto.json.JsonFactory;
Expand Down Expand Up @@ -243,7 +244,7 @@ private WebSocket createWebsocket() {
try {
ws = webSocketFactory.createSocket(messagingConfiguration.getEndpointUri());
} catch (final IOException e) {
throw ConnectException.of(sessionId, e);
throw MessagingException.connectFailed(sessionId, e);
}
ws.addHeader("User-Agent", DITTO_CLIENT_USER_AGENT);
ws.setMaxPayloadSize(256 * 1024); // 256 KiB
Expand Down Expand Up @@ -275,11 +276,11 @@ private <T> T safeGet(final Future<T> future) {

private <T> T handleInterruptedException(final InterruptedException e) {
Thread.currentThread().interrupt();
throw ConnectException.interrupted(sessionId, e);
throw MessagingException.connectInterrupted(sessionId, e);
}

private <T> T handleTimeoutException(final TimeoutException e) {
throw ConnectException.timeout(sessionId, e);
throw MessagingException.connectTimeout(sessionId, e);
}

private <T> T handleExecutionException(final ExecutionException e) {
Expand Down Expand Up @@ -352,7 +353,8 @@ private static ExecutorService createConnectionExecutor() {
@Override
public void send(final Message<?> message, final TopicPath.Channel channel) {
final DittoHeadersBuilder headersBuilder = DittoHeaders.newBuilder();
message.getCorrelationId().ifPresent(headersBuilder::correlationId);
final Optional<String> optionalCorrelationId = message.getCorrelationId();
optionalCorrelationId.ifPresent(headersBuilder::correlationId);
final DittoHeaders dittoHeaders = headersBuilder.build();

final ThingId thingId = message.getThingEntityId();
Expand All @@ -372,11 +374,10 @@ public void send(final Message<?> message, final TopicPath.Channel channel) {
: SendThingMessage.of(thingId, message, dittoHeaders);
adaptable = tryToConvertToAdaptable(messageCommand);

message.getCorrelationId().ifPresent(cId ->
message.getResponseConsumer().ifPresent(responseConsumer ->
messageCommandResponseConsumers.put(cId, responseConsumer)
)
);
final Optional<MessageResponseConsumer<?>> optionalResponseConsumer = message.getResponseConsumer();
if (optionalCorrelationId.isPresent() && optionalResponseConsumer.isPresent()) {
messageCommandResponseConsumers.put(optionalCorrelationId.get(), optionalResponseConsumer.get());
}
}
doSendAdaptable(adaptable);
}
Expand Down Expand Up @@ -693,14 +694,12 @@ public void onError(final WebSocket websocket, final WebSocketException cause) {
private void handleReconnectionIfEnabled() {

if (messagingConfiguration.isReconnectEnabled()) {
if (initiallyConnected.get() && reconnecting.compareAndSet(false, true)) {
// reconnect in a while if client was initially connected and we are not reconnecting already
if (null != reconnectExecutor) {
LOGGER.info("Client <{}>: Reconnection is enabled. Reconnecting in <{}> seconds ...",
sessionId, RECONNECTION_TIMEOUT_SECONDS);
reconnectExecutor.schedule(this::initWebSocketConnectionWithReconnect, RECONNECTION_TIMEOUT_SECONDS,
TimeUnit.SECONDS);
}
// reconnect in a while if client was initially connected and we are not reconnecting already
if (initiallyConnected.get() && reconnecting.compareAndSet(false, true) && null != reconnectExecutor) {
LOGGER.info("Client <{}>: Reconnection is enabled. Reconnecting in <{}> seconds ...",
sessionId, RECONNECTION_TIMEOUT_SECONDS);
reconnectExecutor.schedule(this::initWebSocketConnectionWithReconnect, RECONNECTION_TIMEOUT_SECONDS,
TimeUnit.SECONDS);
}
} else {
LOGGER.info("Client <{}>: Reconnection is NOT enabled. Closing client ...",
Expand Down Expand Up @@ -914,8 +913,9 @@ private void handleTwinMessage(final String message, final CharSequence correlat
LOGGER.debug("Client <{}>: Received TWIN Response JSON: {}", sessionId, message);
if (signal instanceof ThingErrorResponse) {
final DittoRuntimeException cre = ((ErrorResponse) signal).getDittoRuntimeException();
final String description = cre.getDescription().orElse("");
LOGGER.warn("Client <{}>: Got TWIN ThingErrorResponse: <{}: {} - {}>", sessionId,
cre.getClass().getSimpleName(), cre.getMessage(), cre.getDescription().orElse(""));
cre.getClass().getSimpleName(), cre.getMessage(), description);
}
commandResponseConsumer.accept((ThingCommandResponse) signal);
} else if (signal instanceof ThingEvent) {
Expand Down Expand Up @@ -948,8 +948,9 @@ private void handleLiveMessage(final String message, final CharSequence correlat
handleLiveCommand(LiveCommandFactory.getInstance().getLiveCommand((Command) jsonifiable));
} else if (jsonifiable instanceof ThingErrorResponse) {
final DittoRuntimeException cre = ((ErrorResponse) jsonifiable).getDittoRuntimeException();
final String description = cre.getDescription().orElse("");
LOGGER.warn("Client <{}>: Got LIVE ThingErrorResponse: <{}: {} - {}>", sessionId,
cre.getClass().getSimpleName(), cre.getMessage(), cre.getDescription().orElse(""));
cre.getClass().getSimpleName(), cre.getMessage(), description);
if (messageCommandResponseConsumers.containsKey(correlationId.toString())) {
handleLiveMessageResponse((ThingErrorResponse) jsonifiable);
} else {
Expand Down Expand Up @@ -1084,6 +1085,35 @@ private LimitedHashMap(final int maxSize) {
protected boolean removeEldestEntry(final Map.Entry<K, V> eldest) {
return size() > maxSize;
}

@Override
public boolean equals(@Nullable final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
if (!super.equals(o)) {
return false;
}
final LimitedHashMap<?, ?> that = (LimitedHashMap<?, ?>) o;
return maxSize == that.maxSize;
}

@Override
public int hashCode() {
return Objects.hash(super.hashCode(), maxSize);
}

@Override
public String toString() {
return getClass().getSimpleName() + " [" +
super.toString() +
", maxSize=" + maxSize +
"]";
}

}

}
Expand Up @@ -46,7 +46,7 @@
import org.eclipse.ditto.client.live.LiveThingHandle;
import org.eclipse.ditto.client.live.messages.MessageSender;
import org.eclipse.ditto.client.live.messages.MessageSerializer;
import org.eclipse.ditto.client.messaging.ConnectException;
import org.eclipse.ditto.client.messaging.MessagingException;
import org.eclipse.ditto.client.messaging.MessagingProvider;
import org.eclipse.ditto.client.messaging.MessagingProviders;
import org.eclipse.ditto.client.options.Options;
Expand Down Expand Up @@ -281,7 +281,7 @@ public void shouldBeAbleToResolveBundlesOfUsedDependencies() {
// ditto-client:
LOG.info("Ensuring ditto-client is usable from OSGi..");
checkBundleIsPresentInstalledAndActive(FrameworkUtil.getBundle(DittoClient.class));
checkBundleIsPresentInstalledAndActive(FrameworkUtil.getBundle(ConnectException.class));
checkBundleIsPresentInstalledAndActive(FrameworkUtil.getBundle(MessagingException.class));
checkBundleIsPresentInstalledAndActive(FrameworkUtil.getBundle(MessageSender.class));
checkBundleIsPresentInstalledAndActive(FrameworkUtil.getBundle(TwinThingHandle.class));
checkBundleIsPresentInstalledAndActive(FrameworkUtil.getBundle(LiveThingHandle.class));
Expand Down
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.ditto.client.authentication;

import static org.mutabilitydetector.unittesting.MutabilityAssert.assertInstancesOf;
import static org.mutabilitydetector.unittesting.MutabilityMatchers.areImmutable;

import org.junit.Test;

import nl.jqno.equalsverifier.EqualsVerifier;

/**
* Unit test for {@link AuthenticationException}.
*/
public final class AuthenticationExceptionTest {

@Test
public void assertImmutability() {
assertInstancesOf(AuthenticationException.class, areImmutable());
}

}

0 comments on commit 1023c61

Please sign in to comment.