/** * Returns a new {@code ConnectionBuilder} object. * * @param connection the connection to use for initializing the builder. * @return new instance of {@code ImmutableConnectionBuilder}. * @throws NullPointerException if {@code connection} is {@code null}. */ public static ConnectionBuilder getBuilder(final Connection connection) { checkNotNull(connection, "Connection"); return new Builder(connection.getConnectionType()) .id(connection.getId()) .connectionStatus(connection.getConnectionStatus()) .credentials(connection.getCredentials().orElse(null)) .uri(connection.getUri()) .trustedCertificates(connection.getTrustedCertificates().orElse(null)) .failoverEnabled(connection.isFailoverEnabled()) .validateCertificate(connection.isValidateCertificates()) .processorPoolSize(connection.getProcessorPoolSize()) .sources(connection.getSources()) .targets(connection.getTargets()) .clientCount(connection.getClientCount()) .specificConfig(connection.getSpecificConfig()) .mappingContext(connection.getMappingContext().orElse(null)) .name(connection.getName().orElse(null)) .tags(connection.getTags()); }
@Override public Optional<JsonValue> getEntity(final JsonSchemaVersion schemaVersion) { return Optional.ofNullable(connectionCreated).map(connection -> connection.toJson(schemaVersion, FieldType.notHidden())); }
private static void validateFormatOfCertificates(final Connection connection, final DittoHeaders dittoHeaders) { final Optional<String> trustedCertificates = connection.getTrustedCertificates(); final Optional<Credentials> credentials = connection.getCredentials(); // check if there are certificates to check if (trustedCertificates.isPresent() || credentials.isPresent()) { credentials.orElseGet(ClientCertificateCredentials::empty) .accept(SSLContextCreator.fromConnection(connection, dittoHeaders)); } }
private static void validateAddresses(final Connection connection, final DittoHeaders dittoHeaders) { connection.getSources() .stream() .flatMap(source -> source.getAddresses().stream()) .forEach(a -> validateAddress(a, true, dittoHeaders)); // no wildcards allowed for publish targets connection.getTargets() .stream() .map(Target::getAddress) .forEach(a -> validateAddress(a, false, dittoHeaders)); }
MqttConnectionSettings createMqttConnectionSettings(final Connection connection, final DittoHeaders dittoHeaders) { final String uri = connection.getUri(); MqttConnectionSettings connectionSettings = MqttConnectionSettings .create(uri, connection.getId(), new MemoryPersistence()); connectionSettings = connectionSettings.withAutomaticReconnect(connection.isFailoverEnabled()); final Optional<String> possibleUsername = connection.getUsername(); final Optional<String> possiblePassword = connection.getPassword(); if (possibleUsername.isPresent() && possiblePassword.isPresent()) { connectionSettings = connectionSettings.withAuth(possibleUsername.get(), possiblePassword.get()); } if (isSecureConnection(connection)) { connectionSettings = applySSLSocketFactory(connection, connectionSettings, dittoHeaders); } return connectionSettings; }
@Override public String getConnectionId() { return connection.getId(); }
@Test public void createMinimalConnectionConfigurationInstance() { final Connection connection = ConnectivityModelFactory.newConnectionBuilder(ID, TYPE, STATUS, URI) .sources(SOURCES) .targets(TARGETS) .build(); assertThat(connection.getId()).isEqualTo(ID); assertThat((Object) connection.getConnectionType()).isEqualTo(TYPE); assertThat(connection.getUri()).isEqualTo(URI); assertThat(connection.getSources()).isEqualTo(SOURCES); }
private void validateSourceAndTargetAddressesAreNonempty(final Connection connection, final DittoHeaders dittoHeaders) { connection.getSources().forEach(source -> { if (source.getAddresses().isEmpty() || source.getAddresses().contains("")) { final String location = String.format("Source %d of connection <%s>", source.getIndex(), connection.getId()); throw emptyAddressesError(location, dittoHeaders); } }); connection.getTargets().forEach(target -> { if (target.getAddress().isEmpty()) { final String location = String.format("Targets of connection <%s>", connection.getId()); throw emptyAddressesError(location, dittoHeaders); } target.getTopics().forEach(topic -> topic.getFilter().ifPresent(filter -> { // will throw an InvalidRqlExpressionException if the RQL expression was not valid: queryFilterCriteriaFactory.filterCriteria(filter, dittoHeaders); })); }); }
@Override public ConnectionFactory createConnectionFactory(final Connection connection, final ExceptionHandler exceptionHandler) { checkNotNull(connection, "Connection"); checkNotNull(exceptionHandler, "Exception Handler"); try { final ConnectionFactory connectionFactory = new CustomConnectionFactory(); if (SECURE_AMQP_SCHEME.equalsIgnoreCase(connection.getProtocol())) { if (connection.isValidateCertificates()) { final SSLContextCreator sslContextCreator = SSLContextCreator.fromConnection(connection, null); connectionFactory.useSslProtocol(sslContextCreator.withoutClientCertificate()); } else { // attention: this accepts all certificates whether they are valid or not connectionFactory.useSslProtocol(); } } connectionFactory.setUri(connection.getUri()); // this makes no difference as the used newmotion client always sets the AutomaticRecoveryEnabled to false: connectionFactory.setAutomaticRecoveryEnabled(connection.isFailoverEnabled()); connectionFactory.setExceptionHandler(exceptionHandler); configureConnectionFactory(connectionFactory, connection.getSpecificConfig()); return connectionFactory; } catch (final NoSuchAlgorithmException | KeyManagementException | URISyntaxException e) { LOGGER.warn(e.getMessage()); throw new IllegalStateException("Failed to create RabbitMQ connection factory.", e); } }
private static void validateUriByPaho(final Connection connection, final DittoHeaders dittoHeaders) { try { MqttConnectOptions.validateURI(connection.getUri()); } catch (final IllegalArgumentException e) { final String location = String.format("Connection with ID ''%s''", connection.getId()); final String configName = Connection.JsonFields.URI.getPointer().toString(); final String description = "Hint: MQTT connection URI may not have trailing '/' or any other path component."; throw invalidValueForConfig(connection.getUri(), configName, location) .description(description) .dittoHeaders(dittoHeaders) .build(); } }
private static ConnectionFailedException newConnectionFailedException(final Connection connection, final DittoHeaders dittoHeaders) { return ConnectionFailedException .newBuilder(connection.getId()) .dittoHeaders(dittoHeaders) .description("Could not establish a connection on '" + connection.getHostname() + ":" + connection.getPort() + "'. Make sure the " + "endpoint is reachable and that no firewall prevents the connection.") .build(); }
getContext().become(connectionCreatedBehaviour); if (ConnectionStatus.OPEN.equals(connection.getConnectionStatus())) { log.debug("Connection <{}> has status <{}> and will therefore be opened.", connection.getId(), connection.getConnectionStatus().getName()); final OpenConnection openConnection = OpenConnection.of(connectionId, command.getDittoHeaders()); askClientActor(openConnection, } else { log.debug("Connection <{}> has status <{}> and will therefore stay closed.", connection.getId(), connection.getConnectionStatus().getName()); respondWithCreateConnectionResponse(connection, command, origin);
/** * @return whether this client is consuming at all */ protected final boolean isConsuming() { return !connection().getSources().isEmpty(); }
/** * Check a connection for errors and throw them. * * @param connection the connection to validate. * @param dittoHeaders headers of the command that triggered the connection validation. * @throws org.eclipse.ditto.model.base.exceptions.DittoRuntimeException if the connection has errors. * @throws java.lang.IllegalStateException if the connection type is not known. */ void validate(final Connection connection, final DittoHeaders dittoHeaders) { final AbstractProtocolValidator spec = specMap.get(connection.getConnectionType()); validateSourceAndTargetAddressesAreNonempty(connection, dittoHeaders); validateFormatOfCertificates(connection, dittoHeaders); if (spec != null) { // throw error at validation site for clarity of stack trace spec.validate(connection, dittoHeaders); } else { throw new IllegalStateException("Unknown connection type: " + connection); } }
/** * Creates Akka configuration object for this actor. * * @param connection the connection. * @param conciergeForwarder the actor used to send signals to the concierge service. * @return the Akka configuration Props object. */ public static Props props(final Connection connection, final ActorRef conciergeForwarder) { return Props.create(MqttClientActor.class, validateConnection(connection), connection.getConnectionStatus(), conciergeForwarder); }
private MqttConnectionSettings applySSLSocketFactory(final Connection connection, final MqttConnectionSettings connectionSettings, final DittoHeaders dittoHeaders) { final SSLContextCreator sslContextCreator = connection.isValidateCertificates() ? SSLContextCreator.fromConnection(connection, dittoHeaders) : SSLContextCreator.withTrustManager(ACCEPT_ANY_TRUST_MANAGER, dittoHeaders); final Credentials clientCredentials = connection.getCredentials().orElseGet(ClientCertificateCredentials::empty); final SSLContext sslContext = clientCredentials.accept(sslContextCreator); return SocketFactoryExtension.withSocketFactory(connectionSettings, sslContext.getSocketFactory()); }
/** * Check whether the URI scheme of the connection belongs to an accepted scheme. * * @param connection the connection to check. * @param dittoHeaders headers of the command that triggered the connection validation. * @param acceptedSchemes valid URI schemes for the connection type. * @param protocolName protocol name of the connection type. * @throws DittoRuntimeException if the URI scheme is not accepted. */ protected static void validateUriScheme(final Connection connection, final DittoHeaders dittoHeaders, final Collection<String> acceptedSchemes, final String protocolName) { if (!acceptedSchemes.contains(connection.getProtocol())) { final String message = MessageFormat.format("The URI scheme ''{0}'' is not valid for {1}.", connection.getProtocol(), protocolName); final String description = MessageFormat.format("Accepted URI schemes are: {0}", String.join(", ", acceptedSchemes)); throw ConnectionUriInvalidException.newBuilder(connection.getUri()) .message(message) .description(description) .dittoHeaders(dittoHeaders) .build(); } }
/** * Starts the {@link MessageMappingProcessorActor} responsible for payload transformation/mapping as child actor * behind a (cluster node local) RoundRobin pool and a dynamic resizer from the current mapping context. */ protected Either<DittoRuntimeException, ActorRef> startMessageMappingProcessor() { final MappingContext mappingContext = stateData().getConnection().getMappingContext().orElse(null); return startMessageMappingProcessor(mappingContext); }
@Override protected FSMStateFunctionBuilder<BaseClientState, BaseClientData> inTestingState() { return super.inTestingState() .event(Status.Status.class, (e, d) -> !Objects.equals(getSender(), getSelf()), this::handleStatusReportFromChildren) .event(ClientConnected.class, BaseClientData.class, (event, data) -> { final String url = data.getConnection().getUri(); final String message = "mqtt connection to " + url + " established successfully"; completeTestConnectionFuture(new Status.Success(message), data); return stay(); }) .event(ConnectionFailure.class, BaseClientData.class, (event, data) -> { completeTestConnectionFuture(new Status.Failure(event.getFailure().cause()), data); return stay(); }); }
.match(ConnectionCreated.class, event -> restoreConnection(event.getConnection())) .match(ConnectionModified.class, event -> restoreConnection(event.getConnection())) .match(ConnectionOpened.class, event -> restoreConnection(connection != null ? connection.toBuilder() .connectionStatus(ConnectionStatus.OPEN).build() : null)) .match(ConnectionClosed.class, event -> restoreConnection(connection != null ? connection.toBuilder() .connectionStatus(ConnectionStatus.CLOSED).build() : null)) .match(ConnectionDeleted.class, event -> restoreConnection(null)) log.info("Connection <{}> was recovered: {}", connectionId, connection); if (connection != null) { if (ConnectionStatus.OPEN.equals(connection.getConnectionStatus())) { log.debug("Opening connection <{}> after recovery.", connectionId);