Search in sources :

Example 1 with UriConversion

use of io.neonbee.endpoint.odatav4.ODataV4Endpoint.UriConversion in project neonbee by SAP.

the class ODataV4EndpointTest method provideWorkingDirectoryBuilder.

@Override
protected WorkingDirectoryBuilder provideWorkingDirectoryBuilder(TestInfo testInfo, VertxTestContext testContext) {
    return super.provideWorkingDirectoryBuilder(testInfo, testContext).setCustomTask(root -> {
        // the server verticle should either use strict, cds or loose URI mapping
        String testMethodName = testInfo.getTestMethod().map(Method::getName).orElse(EMPTY);
        UriConversion uriConversion = STRICT;
        if (testMethodName.contains("LooseUriConversion")) {
            uriConversion = LOOSE;
        } else if (testMethodName.contains("CDSUriConversion")) {
            uriConversion = CDS;
        }
        DeploymentOptions opts = WorkingDirectoryBuilder.readDeploymentOptions(ServerVerticle.class, root);
        EndpointConfig epc = new EndpointConfig().setType(ODataV4Endpoint.class.getName()).setAdditionalConfig(new JsonObject().put(CONFIG_URI_CONVERSION, uriConversion.toString()));
        ServerConfig sc = new ServerConfig(opts.getConfig()).setEndpointConfigs(List.of(epc));
        opts.setConfig(sc.toJson());
        WorkingDirectoryBuilder.writeDeploymentOptions(ServerVerticle.class, opts, root);
    });
}
Also used : ServerConfig(io.neonbee.config.ServerConfig) DeploymentOptions(io.vertx.core.DeploymentOptions) UriConversion(io.neonbee.endpoint.odatav4.ODataV4Endpoint.UriConversion) JsonObject(io.vertx.core.json.JsonObject) EndpointConfig(io.neonbee.config.EndpointConfig)

Example 2 with UriConversion

use of io.neonbee.endpoint.odatav4.ODataV4Endpoint.UriConversion in project neonbee by SAP.

the class ODataV4Endpoint method createEndpointRouter.

@Override
public Future<Router> createEndpointRouter(Vertx vertx, String basePath, JsonObject config) {
    Router router = Router.router(vertx);
    // true if the router was initialized already
    AtomicBoolean initialized = new AtomicBoolean();
    AtomicReference<Map<String, EntityModel>> models = new AtomicReference<>();
    // the URI convention used to expose the given service in the endpoint.
    UriConversion uriConversion = UriConversion.byName(config.getString("uriConversion", STRICT.name()));
    // a block / allow list of all entities that should be exposed via this endpoint. the entity name is always
    // matched against the full qualified name of the entity in question (URI conversion is applied by NeonBee).
    RegexBlockList exposedEntities = RegexBlockList.fromJson(config.getValue("exposedEntities"));
    // Register the event bus consumer first, otherwise it could happen that during initialization we are missing an
    // update to the data model, a refresh of the router will only be triggered in case it is already initialized.
    // This is a NON-local consumer, this means the reload could be triggered from anywhere, however currently the
    // reload is only triggered in case the EntityModelManager reloads the models locally (and triggers a local
    // publish of the message, thus only triggering the routers to be reloaded on the local instance).
    vertx.eventBus().consumer(EVENT_BUS_MODELS_LOADED_ADDRESS, message -> {
        // do not refresh the router if it wasn't even initialized
        if (initialized.get()) {
            refreshRouter(vertx, router, basePath, uriConversion, exposedEntities, models);
        }
    });
    // This router is initialized lazy, this means that all required routes will be populated on first request to
    // said router, not before. This comes with three major advantages: a) it makes the initialization code more
    // easy, as in case we'd first register to the event handler, we'd always have to check if the model is loaded
    // already and potentially have to deal with a race condition b) no model is loaded / routes are initialized if
    // when NeonBee is started and / or in case the endpoint is not used.
    Route initialRoute = router.route();
    initialRoute.handler(routingContext -> new SharedDataAccessor(vertx, ODataV4Endpoint.class).getLocalLock(asyncLock -> (!initialized.getAndSet(true) ? refreshRouter(vertx, router, basePath, uriConversion, exposedEntities, models) : succeededFuture()).onComplete(handler -> {
        // wait for the refresh to finish (the result doesn't matter), remove the initial route, as
        // this will redirect all requests to the registered service endpoint handlers (if non have
        // been registered, e.g. due to a failure in model loading, it'll result in an 404). Could
        // have been removed already by refreshRouter, we don't care!
        initialRoute.remove();
        if (asyncLock.succeeded()) {
            // releasing the lock will cause other requests unblock and not call the initial route
            asyncLock.result().release();
        }
        // let the router again handle the context again, now with either all service endpoints
        // registered, or none in case there have been a failure while loading the models.
        // NOTE: Re-route is the only elegant way I found to restart the current router to take
        // the new routes! Might consider checking again with the Vert.x 4.0 release.
        routingContext.reroute(routingContext.request().uri());
    })));
    return succeededFuture(router);
}
Also used : Future.succeededFuture(io.vertx.core.Future.succeededFuture) LoggingFacade(io.neonbee.logging.LoggingFacade) HttpServerRequest(io.vertx.core.http.HttpServerRequest) FORBIDDEN(io.netty.handler.codec.http.HttpResponseStatus.FORBIDDEN) Strings.nullToEmpty(com.google.common.base.Strings.nullToEmpty) SharedDataAccessor(io.neonbee.internal.SharedDataAccessor) NeonBee(io.neonbee.NeonBee) Strings.isNullOrEmpty(com.google.common.base.Strings.isNullOrEmpty) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Router(io.vertx.ext.web.Router) UnaryOperator(java.util.function.UnaryOperator) FunctionalHelper.entryConsumer(io.neonbee.internal.helper.FunctionalHelper.entryConsumer) RoutingContext(io.vertx.ext.web.RoutingContext) AtomicReference(java.util.concurrent.atomic.AtomicReference) FunctionalHelper.entryFunction(io.neonbee.internal.helper.FunctionalHelper.entryFunction) Endpoint(io.neonbee.endpoint.Endpoint) EntityModel(io.neonbee.entity.EntityModel) Locale(java.util.Locale) Map(java.util.Map) EndpointConfig(io.neonbee.config.EndpointConfig) JsonObject(io.vertx.core.json.JsonObject) Route(io.vertx.ext.web.Route) EMPTY(io.neonbee.internal.helper.StringHelper.EMPTY) UTF_8(java.nio.charset.StandardCharsets.UTF_8) Vertx(io.vertx.core.Vertx) MoreObjects(com.google.common.base.MoreObjects) Future(io.vertx.core.Future) URLDecoder.decode(java.net.URLDecoder.decode) OlingoEndpointHandler(io.neonbee.endpoint.odatav4.internal.olingo.OlingoEndpointHandler) RegexBlockList(io.neonbee.internal.RegexBlockList) Strings.emptyToNull(com.google.common.base.Strings.emptyToNull) List(java.util.List) STRICT(io.neonbee.endpoint.odatav4.ODataV4Endpoint.UriConversion.STRICT) Optional(java.util.Optional) Pattern(java.util.regex.Pattern) Comparator(java.util.Comparator) EVENT_BUS_MODELS_LOADED_ADDRESS(io.neonbee.entity.EntityModelManager.EVENT_BUS_MODELS_LOADED_ADDRESS) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) RegexBlockList(io.neonbee.internal.RegexBlockList) Router(io.vertx.ext.web.Router) SharedDataAccessor(io.neonbee.internal.SharedDataAccessor) AtomicReference(java.util.concurrent.atomic.AtomicReference) Map(java.util.Map) Route(io.vertx.ext.web.Route)

Example 3 with UriConversion

use of io.neonbee.endpoint.odatav4.ODataV4Endpoint.UriConversion in project neonbee by SAP.

the class ODataReadEntitiesTest method provideWorkingDirectoryBuilder.

@Override
protected WorkingDirectoryBuilder provideWorkingDirectoryBuilder(TestInfo testInfo, VertxTestContext testContext) {
    return super.provideWorkingDirectoryBuilder(testInfo, testContext).setCustomTask(root -> {
        // the server verticle should either use strict, cds or loose URI mapping
        String testMethodName = testInfo.getTestMethod().map(Method::getName).orElse(EMPTY);
        UriConversion uriConversion = STRICT;
        if (testMethodName.contains("LooseUriConversion")) {
            uriConversion = LOOSE;
        } else if (testMethodName.contains("CDSUriConversion")) {
            uriConversion = CDS;
        }
        DeploymentOptions opts = WorkingDirectoryBuilder.readDeploymentOptions(ServerVerticle.class, root);
        EndpointConfig epc = new EndpointConfig().setType(ODataV4Endpoint.class.getName()).setAdditionalConfig(new JsonObject().put(CONFIG_URI_CONVERSION, uriConversion.toString()));
        ServerConfig sc = new ServerConfig(opts.getConfig()).setEndpointConfigs(List.of(epc));
        opts.setConfig(sc.toJson());
        WorkingDirectoryBuilder.writeDeploymentOptions(ServerVerticle.class, opts, root);
    });
}
Also used : ServerConfig(io.neonbee.config.ServerConfig) DeploymentOptions(io.vertx.core.DeploymentOptions) UriConversion(io.neonbee.endpoint.odatav4.ODataV4Endpoint.UriConversion) JsonObject(io.vertx.core.json.JsonObject) EndpointConfig(io.neonbee.config.EndpointConfig)

Aggregations

EndpointConfig (io.neonbee.config.EndpointConfig)3 JsonObject (io.vertx.core.json.JsonObject)3 ServerConfig (io.neonbee.config.ServerConfig)2 UriConversion (io.neonbee.endpoint.odatav4.ODataV4Endpoint.UriConversion)2 DeploymentOptions (io.vertx.core.DeploymentOptions)2 MoreObjects (com.google.common.base.MoreObjects)1 Strings.emptyToNull (com.google.common.base.Strings.emptyToNull)1 Strings.isNullOrEmpty (com.google.common.base.Strings.isNullOrEmpty)1 Strings.nullToEmpty (com.google.common.base.Strings.nullToEmpty)1 NeonBee (io.neonbee.NeonBee)1 Endpoint (io.neonbee.endpoint.Endpoint)1 STRICT (io.neonbee.endpoint.odatav4.ODataV4Endpoint.UriConversion.STRICT)1 OlingoEndpointHandler (io.neonbee.endpoint.odatav4.internal.olingo.OlingoEndpointHandler)1 EntityModel (io.neonbee.entity.EntityModel)1 EVENT_BUS_MODELS_LOADED_ADDRESS (io.neonbee.entity.EntityModelManager.EVENT_BUS_MODELS_LOADED_ADDRESS)1 RegexBlockList (io.neonbee.internal.RegexBlockList)1 SharedDataAccessor (io.neonbee.internal.SharedDataAccessor)1 FunctionalHelper.entryConsumer (io.neonbee.internal.helper.FunctionalHelper.entryConsumer)1 FunctionalHelper.entryFunction (io.neonbee.internal.helper.FunctionalHelper.entryFunction)1 EMPTY (io.neonbee.internal.helper.StringHelper.EMPTY)1