/** * If no context is set on connection level each target and source must have its own context. */ private void checkAuthorizationContextsAreValid() { // if the auth context on connection level is empty, // an auth context is required to be set on each source/target final Set<String> sourcesWithoutAuthContext = sources.stream() .filter(source -> source.getAuthorizationContext().isEmpty()) .flatMap(source -> source.getAddresses().stream()) .collect(Collectors.toSet()); final Set<String> targetsWithoutAuthContext = targets.stream() .filter(target -> target.getAuthorizationContext().isEmpty()) .map(Target::getAddress) .collect(Collectors.toSet()); if (!sourcesWithoutAuthContext.isEmpty() || !targetsWithoutAuthContext.isEmpty()) { final StringBuilder message = new StringBuilder("The "); if (!sourcesWithoutAuthContext.isEmpty()) { message.append("Sources ").append(sourcesWithoutAuthContext); } if (!sourcesWithoutAuthContext.isEmpty() && !targetsWithoutAuthContext.isEmpty()) { message.append(" and "); } if (!targetsWithoutAuthContext.isEmpty()) { message.append("Targets ").append(targetsWithoutAuthContext); } message.append(" are missing an authorization context."); throw ConnectionConfigurationInvalidException.newBuilder(message.toString()).build(); } }
private static void validateSourceEnforcement(@Nullable final Enforcement enforcement, final DittoHeaders dittoHeaders, final Supplier<String> sourceDescription) { if (enforcement != null) { validateEnforcementInput(enforcement, sourceDescription, dittoHeaders); final String dummyThingId = "namespace:name"; final Map<String, String> filtersMap = PlaceholderFilter.filterAddressesAsMap(enforcement.getFilters(), dummyThingId, filter -> { throw invalidValueForConfig(filter, "filters", sourceDescription.get()) .description("Placeholder substitution failed. " + "Please check the placeholder variables against the documentation.") .dittoHeaders(dittoHeaders) .build(); }); filtersMap.forEach((filter, mqttTopic) -> validateMqttTopic(mqttTopic, true, errorMessage -> invalidValueForConfig(filter, "filters", sourceDescription.get()) .description( "The filter is not a valid MQTT topic after placeholder substitution. " + "Wildcard characters are allowed.") .dittoHeaders(dittoHeaders) .build())); } }
@Override protected void validateSource(final Source source, final DittoHeaders dittoHeaders, final Supplier<String> sourceDescription) { if (!(source instanceof MqttSource)) { final String message = MessageFormat.format("Source {0} must be of type MqttSource.", sourceDescription.get()); throw ConnectionConfigurationInvalidException.newBuilder(message) .dittoHeaders(dittoHeaders) .build(); } if (source.getHeaderMapping().isPresent()) { throw ConnectionConfigurationInvalidException.newBuilder("Header mapping is not supported for MQTT " + "sources.").dittoHeaders(dittoHeaders).build(); } final MqttSource mqttSource = (MqttSource) source; validateSourceQoS(mqttSource.getQos(), dittoHeaders, sourceDescription); validateSourceEnforcement(mqttSource.getEnforcement().orElse(null), dittoHeaders, sourceDescription); }
private void modifyConnection(final ModifyConnection command) { final ActorRef origin = getSender(); final ActorRef self = getSelf(); if (connection != null && !connection.getConnectionType().equals(command.getConnection().getConnectionType())) { handleException("modify", origin, ConnectionConfigurationInvalidException .newBuilder("ConnectionType <" + connection.getConnectionType().getName() + "> of existing connection <" + connectionId + "> cannot be changed!") .dittoHeaders(command.getDittoHeaders()) .build() ); return; } persistEvent(ConnectionModified.of(command.getConnection(), command.getDittoHeaders()), persistedEvent -> { restoreConnection(persistedEvent.getConnection()); getContext().become(connectionCreatedBehaviour); // if client actor is started: send an artificial CloseConnection command to gracefully disconnect and stop the child actors askClientActorIfStarted(CloseConnection.of(connectionId, DittoHeaders.empty()), onSuccess -> { final PerformTask modifyTask = createModifyConnectionTask(true, command, origin); self.tell(modifyTask, ActorRef.noSender()); }, error -> handleException("connect-after-modify", origin, error), () -> { final PerformTask modifyTask = createModifyConnectionTask(false, command, origin); self.tell(modifyTask, ActorRef.noSender()); }); }); }
private void modifyConnection(final ModifyConnection command) { final ActorRef origin = getSender(); final ActorRef self = getSelf(); if (connection != null && !connection.getConnectionType().equals(command.getConnection().getConnectionType())) { handleException("modify", origin, ConnectionConfigurationInvalidException .newBuilder("ConnectionType <" + connection.getConnectionType().getName() + "> of existing connection <" + connectionId + "> cannot be changed!") .dittoHeaders(command.getDittoHeaders()) .build() ); return; } persistEvent(ConnectionModified.of(command.getConnection(), command.getDittoHeaders()), persistedEvent -> { restoreConnection(persistedEvent.getConnection()); getContext().become(connectionCreatedBehaviour); // if client actor is started: send an artificial CloseConnection command to gracefully disconnect and stop the child actors askClientActorIfStarted(CloseConnection.of(connectionId, DittoHeaders.empty()), onSuccess -> { final PerformTask modifyTask = createModifyConnectionTask(true, command, origin); self.tell(modifyTask, ActorRef.noSender()); }, error -> handleException("connect-after-modify", origin, error), () -> { final PerformTask modifyTask = createModifyConnectionTask(false, command, origin); self.tell(modifyTask, ActorRef.noSender()); }); }); }
/** * If no context is set on connection level each target and source must have its own context. */ private void checkAuthorizationContextsAreValid() { // if the auth context on connection level is empty, // an auth context is required to be set on each source/target final Set<String> sourcesWithoutAuthContext = sources.stream() .filter(source -> source.getAuthorizationContext().isEmpty()) .flatMap(source -> source.getAddresses().stream()) .collect(Collectors.toSet()); final Set<String> targetsWithoutAuthContext = targets.stream() .filter(target -> target.getAuthorizationContext().isEmpty()) .map(Target::getAddress) .collect(Collectors.toSet()); if (!sourcesWithoutAuthContext.isEmpty() || !targetsWithoutAuthContext.isEmpty()) { final StringBuilder message = new StringBuilder("The "); if (!sourcesWithoutAuthContext.isEmpty()) { message.append("Sources ").append(sourcesWithoutAuthContext); } if (!sourcesWithoutAuthContext.isEmpty() && !targetsWithoutAuthContext.isEmpty()) { message.append(" and "); } if (!targetsWithoutAuthContext.isEmpty()) { message.append("Targets ").append(targetsWithoutAuthContext); } message.append(" are missing an authorization context."); throw ConnectionConfigurationInvalidException.newBuilder(message.toString()).build(); } }
/** * Creates a new {@code Source} object from the specified JSON object. Decides which specific {@link Source} * implementation to choose depending on the given {@link ConnectionType}. * * @param jsonObject a JSON object which provides the data for the Source to be created. * @param index the index to distinguish between sources that would otherwise be different * @param type the connection type required to decide which iplementation of {@link Source} to choose * @return a new Source which is initialised with the extracted data from {@code jsonObject}. * @throws NullPointerException if {@code jsonObject} is {@code null}. * @throws org.eclipse.ditto.json.JsonParseException if {@code jsonObject} is not an appropriate JSON object. */ public static Source sourceFromJson(final JsonObject jsonObject, final int index, final ConnectionType type) { switch (type) { case AMQP_091: case AMQP_10: return ImmutableSource.fromJson(jsonObject, index); case MQTT: return ImmutableMqttSource.fromJson(jsonObject, index); default: throw ConnectionConfigurationInvalidException .newBuilder("Unexpected connection type <" + type + ">") .build(); } }
/** * Creates a new {@code Source} object from the specified JSON object. Decides which specific {@link Source} * implementation to choose depending on the given {@link ConnectionType}. * * @param jsonObject a JSON object which provides the data for the Source to be created. * @param index the index to distinguish between sources that would otherwise be different * @param type the connection type required to decide which iplementation of {@link Source} to choose * @return a new Source which is initialised with the extracted data from {@code jsonObject}. * @throws NullPointerException if {@code jsonObject} is {@code null}. * @throws org.eclipse.ditto.json.JsonParseException if {@code jsonObject} is not an appropriate JSON object. */ public static Source sourceFromJson(final JsonObject jsonObject, final int index, final ConnectionType type) { switch (type) { case AMQP_091: case AMQP_10: return ImmutableSource.fromJson(jsonObject, index); case MQTT: return ImmutableMqttSource.fromJson(jsonObject, index); default: throw ConnectionConfigurationInvalidException .newBuilder("Unexpected connection type <" + type + ">") .build(); } }
/** * Creates a new {@code Target} object from the specified JSON object. Decides which specific {@link Target} * implementation to choose depending on the given {@link ConnectionType}. * * @param jsonObject a JSON object which provides the data for the Target to be created. * @param type the connection type required to decide which iplementation of {@link Source} to choose * @return a new Source Target is initialised with the extracted data from {@code jsonObject}. * @throws NullPointerException if {@code jsonObject} is {@code null}. * @throws org.eclipse.ditto.json.JsonParseException if {@code jsonObject} is not an appropriate JSON object. */ public static Target targetFromJson(final JsonObject jsonObject, final ConnectionType type) { switch (type) { case AMQP_091: case AMQP_10: return ImmutableTarget.fromJson(jsonObject); case MQTT: return ImmutableMqttTarget.fromJson(jsonObject); default: throw ConnectionConfigurationInvalidException .newBuilder("Unexpected connection type <" + type + ">") .build(); } }
/** * Creates a new {@code Target} object from the specified JSON object. Decides which specific {@link Target} * implementation to choose depending on the given {@link ConnectionType}. * * @param jsonObject a JSON object which provides the data for the Target to be created. * @param type the connection type required to decide which iplementation of {@link Source} to choose * @return a new Source Target is initialised with the extracted data from {@code jsonObject}. * @throws NullPointerException if {@code jsonObject} is {@code null}. * @throws org.eclipse.ditto.json.JsonParseException if {@code jsonObject} is not an appropriate JSON object. */ public static Target targetFromJson(final JsonObject jsonObject, final ConnectionType type) { switch (type) { case AMQP_091: case AMQP_10: return ImmutableTarget.fromJson(jsonObject); case MQTT: return ImmutableMqttTarget.fromJson(jsonObject); default: throw ConnectionConfigurationInvalidException .newBuilder("Unexpected connection type <" + type + ">") .build(); } }
private static void validateSourceEnforcement(@Nullable final Enforcement enforcement, final DittoHeaders dittoHeaders, final Supplier<String> sourceDescription) { if (enforcement != null) { validateEnforcementInput(enforcement, sourceDescription, dittoHeaders); final String dummyThingId = "namespace:name"; final Map<String, String> filtersMap = PlaceholderFilter.filterAddressesAsMap(enforcement.getFilters(), dummyThingId, filter -> { throw invalidValueForConfig(filter, "filters", sourceDescription.get()) .description("Placeholder substitution failed. " + "Please check the placeholder variables against the documentation.") .dittoHeaders(dittoHeaders) .build(); }); filtersMap.forEach((filter, mqttTopic) -> validateMqttTopic(mqttTopic, true, errorMessage -> invalidValueForConfig(filter, "filters", sourceDescription.get()) .description( "The filter is not a valid MQTT topic after placeholder substitution. " + "Wildcard characters are allowed.") .dittoHeaders(dittoHeaders) .build())); } }
/** * Constructs a new {@code ConnectionConfigurationInvalidException} object with the exception message extracted from * the given * JSON object. * * @param jsonObject the JSON to read the {@link JsonFields#MESSAGE} field from. * @param dittoHeaders the headers of the command which resulted in this exception. * @return the new ConnectionConfigurationInvalidException. * @throws org.eclipse.ditto.json.JsonMissingFieldException if the {@code jsonObject} does not have the {@link * JsonFields#MESSAGE} field. */ public static ConnectionConfigurationInvalidException fromJson(final JsonObject jsonObject, final DittoHeaders dittoHeaders) { return new Builder() .dittoHeaders(dittoHeaders) .message(readMessage(jsonObject)) .description(readDescription(jsonObject).orElse(DEFAULT_DESCRIPTION)) .href(readHRef(jsonObject).orElse(null)) .build(); }
/** * Constructs a new {@code ConnectionConfigurationInvalidException} object with the exception message extracted from * the given * JSON object. * * @param jsonObject the JSON to read the {@link JsonFields#MESSAGE} field from. * @param dittoHeaders the headers of the command which resulted in this exception. * @return the new ConnectionConfigurationInvalidException. * @throws org.eclipse.ditto.json.JsonMissingFieldException if the {@code jsonObject} does not have the {@link * JsonFields#MESSAGE} field. */ public static ConnectionConfigurationInvalidException fromJson(final JsonObject jsonObject, final DittoHeaders dittoHeaders) { return new Builder() .dittoHeaders(dittoHeaders) .message(readMessage(jsonObject)) .description(readDescription(jsonObject).orElse(DEFAULT_DESCRIPTION)) .href(readHRef(jsonObject).orElse(null)) .build(); }
@Override protected void validateSource(final Source source, final DittoHeaders dittoHeaders, final Supplier<String> sourceDescription) { if (!(source instanceof MqttSource)) { final String message = MessageFormat.format("Source {0} must be of type MqttSource.", sourceDescription.get()); throw ConnectionConfigurationInvalidException.newBuilder(message) .dittoHeaders(dittoHeaders) .build(); } if (source.getHeaderMapping().isPresent()) { throw ConnectionConfigurationInvalidException.newBuilder("Header mapping is not supported for MQTT " + "sources.").dittoHeaders(dittoHeaders).build(); } final MqttSource mqttSource = (MqttSource) source; validateSourceQoS(mqttSource.getQos(), dittoHeaders, sourceDescription); validateSourceEnforcement(mqttSource.getEnforcement().orElse(null), dittoHeaders, sourceDescription); }
@Override protected void validateTarget(final Target target, final DittoHeaders dittoHeaders, final Supplier<String> targetDescription) { if (!(target instanceof MqttTarget)) { final String message = MessageFormat.format("Target {0} must be of type MqttTarget.", targetDescription.get()); throw ConnectionConfigurationInvalidException.newBuilder(message) .dittoHeaders(dittoHeaders) .build(); } if (target.getHeaderMapping().isPresent()) { throw ConnectionConfigurationInvalidException.newBuilder("Header mapping is not supported for MQTT " + "targets.").dittoHeaders(dittoHeaders).build(); } final MqttTarget mqttTarget = (MqttTarget) target; validateTargetQoS(mqttTarget.getQos(), dittoHeaders, targetDescription); }
private static Connection validateConnection(final Connection connection) { try { final URI uri = URI.create(ConnectionBasedJmsConnectionFactory.buildAmqpConnectionUriFromConnection(connection)); ProviderFactory.create(uri); return connection; } catch (final Exception e) { final String errorMessageTemplate = "Failed to instantiate an amqp provider from the given configuration: {0}"; final String errorMessage = MessageFormat.format(errorMessageTemplate, e.getMessage()); throw ConnectionConfigurationInvalidException .newBuilder(errorMessage) .description(e.getMessage()) .cause(e) .build(); } }
private static Connection validateConnection(final Connection connection) { try { final URI uri = URI.create(ConnectionBasedJmsConnectionFactory.buildAmqpConnectionUriFromConnection(connection)); ProviderFactory.create(uri); return connection; } catch (final Exception e) { final String errorMessageTemplate = "Failed to instantiate an amqp provider from the given configuration: {0}"; final String errorMessage = MessageFormat.format(errorMessageTemplate, e.getMessage()); throw ConnectionConfigurationInvalidException .newBuilder(errorMessage) .description(e.getMessage()) .cause(e) .build(); } }
@Override protected void validateTarget(final Target target, final DittoHeaders dittoHeaders, final Supplier<String> targetDescription) { if (!(target instanceof MqttTarget)) { final String message = MessageFormat.format("Target {0} must be of type MqttTarget.", targetDescription.get()); throw ConnectionConfigurationInvalidException.newBuilder(message) .dittoHeaders(dittoHeaders) .build(); } if (target.getHeaderMapping().isPresent()) { throw ConnectionConfigurationInvalidException.newBuilder("Header mapping is not supported for MQTT " + "targets.").dittoHeaders(dittoHeaders).build(); } final MqttTarget mqttTarget = (MqttTarget) target; validateTargetQoS(mqttTarget.getQos(), dittoHeaders, targetDescription); }
private static void validateEnforcementInput(final Enforcement enforcement, final Supplier<String> sourceDescription, final DittoHeaders dittoHeaders) { final SourceAddressPlaceholder sourceAddressPlaceholder = PlaceholderFactory.newSourceAddressPlaceholder(); try { EnforcementFactoryFactory .newEnforcementFilterFactory(enforcement, sourceAddressPlaceholder) .getFilter("dummyTopic"); } catch (final DittoRuntimeException e) { throw invalidValueForConfig(enforcement.getInput(), "input", sourceDescription.get()) .cause(e) .description(MessageFormat.format(ERROR_DESCRIPTION, enforcement.getInput(), sourceAddressPlaceholder.getSupportedNames())) .dittoHeaders(dittoHeaders) .build(); } }
private static void validateEnforcementInput(final Enforcement enforcement, final Supplier<String> sourceDescription, final DittoHeaders dittoHeaders) { final SourceAddressPlaceholder sourceAddressPlaceholder = PlaceholderFactory.newSourceAddressPlaceholder(); try { EnforcementFactoryFactory .newEnforcementFilterFactory(enforcement, sourceAddressPlaceholder) .getFilter("dummyTopic"); } catch (final DittoRuntimeException e) { throw invalidValueForConfig(enforcement.getInput(), "input", sourceDescription.get()) .cause(e) .description(MessageFormat.format(ERROR_DESCRIPTION, enforcement.getInput(), sourceAddressPlaceholder.getSupportedNames())) .dittoHeaders(dittoHeaders) .build(); } }