private Route thingMessages(final RequestContext ctx, final DittoHeaders dittoHeaders, final String thingId, final String inboxOutbox) { final MessageDirection direction = PATH_INBOX.equalsIgnoreCase(inboxOutbox) ? MessageDirection.TO : MessageDirection.FROM; return rawPathPrefix(mergeDoubleSlashes().concat(PathMatchers.segment(PATH_MESSAGES).slash()), () -> // /messages extractUnmatchedPath(msgSubject -> // <msgSubject/with/slashes> parameterOptional(Unmarshaller.sync(Long::parseLong), TIMEOUT_PARAMETER, optionalTimeout -> withCustomRequestTimeout(optionalTimeout, this::checkMessageTimeout, defaultMessageTimeout, timeout -> extractDataBytes(payloadSource -> handleMessage(ctx, payloadSource, buildSendThingMessage( direction, ctx, dittoHeaders, thingId, msgSubject, timeout ) ) ) ) ) ) ); }
/** * PatchMather which matches double slashes in the path as well as single slashes. * * @return a PathMatcher0 merging double slashes in an unmatched path. */ public static PathMatcher0 mergeDoubleSlashes() { return PathMatchers.slash().concat(PathMatchers.slash()) // match 2 slashes, e.g. //foo .orElse(PathMatchers.slash()); // as fallback match one slash, e.g. /foo }
private static Route buildRouteWithServiceNameAndInstance(final RequestContext ctx, final String serviceName, final DittoHeaders dittoHeaders, final RouteBuilderWithOptionalServiceNameAndInstance routeBuilder) { return rawPathPrefix(mergeDoubleSlashes().concat(PathMatchers.segment()), instance -> // /devops/<logging|piggyback>/<serviceName>/<instance> routeBuilder.build(ctx, serviceName, Integer.parseInt(instance), dittoHeaders) ); }
path(segment("products").slash(longSegment()), (productId) ->
private Route policyEntryEntries(final RequestContext ctx, final DittoHeaders dittoHeaders, final String policyId) { return rawPathPrefix(mergeDoubleSlashes().concat(PATH_ENTRIES), () -> // /policies/<policyId>/entries policyEntriesRoute.buildPolicyEntriesRoute(ctx, dittoHeaders, policyId) ); }
private Route featuresEntryInboxOutbox(final RequestContext ctx, final DittoHeaders dittoHeaders, final String thingId) { return rawPathPrefix(mergeDoubleSlashes().concat(PathMatchers.segment()), featureId -> // POST /features/{featureId}/<inbox|outbox> messagesRoute.buildFeaturesInboxOutboxRoute(ctx, dittoHeaders, thingId, featureId) ); } }
/** * Builds the {@code /policies} route. * * @return the {@code /policies} route. */ public Route buildPoliciesRoute(final RequestContext ctx, final DittoHeaders dittoHeaders) { return rawPathPrefix(mergeDoubleSlashes().concat(PATH_POLICIES), () -> rawPathPrefix(mergeDoubleSlashes().concat(PathMatchers.segment()), policyId -> // /policies/<policyId> route( policyEntry(ctx, dittoHeaders, policyId), policyEntryEntries(ctx, dittoHeaders, policyId) ) ) ); }
public Route buildStatsRoute(final String correlationId) { return Directives.rawPathPrefix(CustomPathMatchers.mergeDoubleSlashes().concat(STATISTICS_PATH_PREFIX), () -> // /stats/* extractRequestContext(ctx -> get(() -> // GET buildSubRoutes(ctx, correlationId) ) ) ); }
/** * Builds the {@code /{inbox|outbox}} sub route for the features route. * * @return the {@code /{inbox|outbox}} route. */ public Route buildFeaturesInboxOutboxRoute(final RequestContext ctx, final DittoHeaders dittoHeaders, final String thingId, final String featureId) { return rawPathPrefix(mergeDoubleSlashes().concat(PathMatchers.segment(INBOX_OUTBOX_PATTERN)), inboxOutbox -> // /<inbox|outbox> post(() -> featureMessages(ctx, dittoHeaders, thingId, featureId, inboxOutbox)) ); }
/** * Describes {@code /things} SSE route. * * @return {@code /things} SSE route. */ @SuppressWarnings("squid:S1172") // allow unused ctx-Param in order to have a consistent route-"interface" public Route buildThingsSseRoute(final RequestContext ctx, final Supplier<DittoHeaders> dittoHeadersSupplier) { return rawPathPrefix(mergeDoubleSlashes().concat(PATH_THINGS), () -> pathEndOrSingleSlash(() -> get(() -> headerValuePF(AcceptHeaderExtractor.INSTANCE, accept -> doBuildThingsSseRoute(dittoHeadersSupplier.get()) ) ) ) ); }
/** * Builds the {@code /search} route. * * @return the {@code /search}} route. */ public Route buildSearchRoute(final RequestContext ctx, final DittoHeaders dittoHeaders) { return Directives.rawPathPrefix(CustomPathMatchers.mergeDoubleSlashes().concat(PATH_SEARCH), () -> Directives.rawPathPrefix(CustomPathMatchers.mergeDoubleSlashes().concat(PATH_THINGS), () -> // /search/things Directives.route( // /search/things/count path(PATH_COUNT, () -> countThings(ctx, dittoHeaders)), // /search/things pathEndOrSingleSlash(() -> searchThings(ctx, dittoHeaders)) ) ) ); }
private static Route buildRouteWithServiceNameAndOptionalInstance(final RequestContext ctx, final DittoHeaders dittoHeaders, final RouteBuilderWithOptionalServiceNameAndInstance routeBuilder) { return rawPathPrefix(mergeDoubleSlashes().concat(PathMatchers.segment()), serviceName -> route( // /devops/<logging|piggyback>/<serviceName>/<instance> buildRouteWithServiceNameAndInstance(ctx, serviceName, dittoHeaders, routeBuilder), // /devops/<logging|piggyback>/<serviceName> routeBuilder.build(ctx, serviceName, null, dittoHeaders) ) ); }
/** * @return the {@code /devops} route. */ public Route buildDevopsRoute(final RequestContext ctx) { return rawPathPrefix(mergeDoubleSlashes().concat(PATH_DEVOPS), () -> // /devops authenticateDevopsBasic(REALM_DEVOPS, parameterOptional(Unmarshaller.sync(Long::parseLong), TIMEOUT_PARAMETER, optionalTimeout -> route( rawPathPrefix(mergeDoubleSlashes().concat(PATH_LOGGING), () -> // /devops/logging logging(ctx, createHeaders(optionalTimeout)) ), rawPathPrefix(mergeDoubleSlashes().concat(PATH_PIGGYBACK), () -> // /devops/piggyback piggyback(ctx, createHeaders(optionalTimeout)) ) ) ) )); }
private Route ensureSchemaVersion(final Function<Integer, Route> inner) { return rawPathPrefix(mergeDoubleSlashes().concat(PathMatchers.integerSegment()), apiVersion -> { // /xx/<schemaVersion> if (supportedSchemaVersions.contains(apiVersion)) { try { return inner.apply(apiVersion); } catch (final RuntimeException e) { throw e; // rethrow RuntimeExceptions } catch (final Exception e) { throw new IllegalStateException("Unexpected checked exception", e); } } else { final CommandNotSupportedException commandNotSupportedException = CommandNotSupportedException.newBuilder(apiVersion).build(); return complete( HttpResponse.create().withStatus(commandNotSupportedException.getStatusCode().toInt()) .withEntity(ContentTypes.APPLICATION_JSON, ByteString.fromString(commandNotSupportedException.toJsonString()))); } }); }
/** * Builds the {@code /{inbox|outbox}} sub route for the things route. * * @return the {@code /{inbox|outbox}} route. */ public Route buildThingsInboxOutboxRoute(final RequestContext ctx, final DittoHeaders dittoHeaders, final String thingId) { return route( claimMessages(ctx, dittoHeaders, thingId), // /inbox/claim rawPathPrefix(mergeDoubleSlashes().concat(PathMatchers.segment(INBOX_OUTBOX_PATTERN)), inboxOutbox -> // /<inbox|outbox> post(() -> thingMessages(ctx, dittoHeaders, thingId, inboxOutbox)) ) ); }
private Route ws(final RequestContext ctx, final String correlationId) { return rawPathPrefix(mergeDoubleSlashes().concat(WS_PATH_PREFIX), () -> // /ws ensureSchemaVersion(wsVersion -> // /ws/<wsVersion> wsAuthentication(correlationId, authContextWithPrefixedSubjects -> mapAuthorizationContext(correlationId, wsVersion, authContextWithPrefixedSubjects, authContext -> withDittoHeaders(authContext, wsVersion, correlationId, ctx, null, CustomHeadersHandler.RequestType.WS, dittoHeaders -> { final String userAgent = extractUserAgent(ctx).orElse(null); final ProtocolAdapter chosenProtocolAdapter = protocolAdapterProvider.getProtocolAdapter( userAgent); return websocketRoute.buildWebsocketRoute(wsVersion, correlationId, authContext, dittoHeaders, chosenProtocolAdapter); } ) ) ) ) ); }
private Route claimMessages(final RequestContext ctx, final DittoHeaders dittoHeaders, final String thingId) { return rawPathPrefix(mergeDoubleSlashes().concat(PATH_INBOX), () -> // /inbox rawPathPrefix(mergeDoubleSlashes().concat(PATH_CLAIM), () -> // /inbox/claim post(() -> pathEndOrSingleSlash(() -> parameterOptional(Unmarshaller.sync(Long::parseLong), TIMEOUT_PARAMETER, optionalTimeout -> withCustomRequestTimeout(optionalTimeout, this::checkClaimTimeout, defaultClaimTimeout, timeout -> extractDataBytes(payloadSource -> handleMessage(ctx, payloadSource, buildSendClaimMessage( ctx, dittoHeaders, thingId, timeout ) ) ) ) ) ) ) ) ); }
/** * Builds the {@code /status} route. * * @return the {@code /status} route. */ public Route buildOverallStatusRoute() { return rawPathPrefix(mergeDoubleSlashes().concat(PATH_OVERALL), () -> // /overall/* authenticateDevopsBasic(REALM_DEVOPS, get(() -> // GET // /overall/status // /overall/status/health // /overall/status/cluster rawPathPrefix(mergeDoubleSlashes().concat(PATH_STATUS), () -> route( // /status pathEndOrSingleSlash( () -> completeWithFuture(createOverallStatusResponse())), // /status/health path(PATH_HEALTH, () -> completeWithFuture(createOverallHealthResponse())), path(PATH_CLUSTER, () -> complete( // /status/cluster HttpResponse.create().withStatus(StatusCodes.OK) .withEntity(ContentTypes.APPLICATION_JSON, clusterStateSupplier.get().toJson().toString())) ) )) ))); }
/** * Builds the {@code /features} route. * * @return the {@code /features} route. */ public Route buildFeaturesRoute(final RequestContext ctx, final DittoHeaders dittoHeaders, final String thingId) { return rawPathPrefix(mergeDoubleSlashes().concat(PATH_PREFIX), () -> Directives.route( features(ctx, dittoHeaders, thingId), featuresEntry(ctx, dittoHeaders, thingId), featuresEntryDefinition(ctx, dittoHeaders, thingId), featuresEntryProperties(ctx, dittoHeaders, thingId), featuresEntryPropertiesEntry(ctx, dittoHeaders, thingId), featuresEntryInboxOutbox(ctx, dittoHeaders, thingId) ) ); }