All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.micronaut.runtime.http.scope.RequestCustomScope Maven / Gradle / Ivy

There is a newer version: 4.7.9
Show newest version
/*
 * Copyright 2017-2020 original authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.micronaut.runtime.http.scope;

import io.micronaut.context.event.ApplicationEventListener;
import io.micronaut.context.scope.AbstractConcurrentCustomScope;
import io.micronaut.context.scope.BeanCreationContext;
import io.micronaut.context.scope.CreatedBean;
import io.micronaut.core.annotation.NonNull;
import io.micronaut.core.convert.value.MutableConvertibleValues;
import io.micronaut.core.util.ArgumentUtils;
import io.micronaut.http.HttpRequest;
import io.micronaut.http.context.ServerRequestContext;
import io.micronaut.http.context.event.HttpRequestTerminatedEvent;
import io.micronaut.inject.BeanIdentifier;
import jakarta.inject.Singleton;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * A {@link io.micronaut.context.scope.CustomScope} that creates a new bean for every HTTP request.
 *
 * @author James Kleeh
 * @author Marcel Overdijk
 * @since 1.2.0
 */
@Singleton
class RequestCustomScope extends AbstractConcurrentCustomScope implements ApplicationEventListener {
    /**
     * The request attribute to store scoped beans in.
     */
    public static final String SCOPED_BEANS_ATTRIBUTE = "io.micronaut.http.SCOPED_BEANS";

    /**
     * Creates the request scope for the given context.
     *
     */
    public RequestCustomScope() {
        super(RequestScope.class);
    }

    @Override
    public void close() {
        ServerRequestContext.currentRequest().ifPresent(this::destroyBeans);
    }

    @Override
    public boolean isRunning() {
        return ServerRequestContext.currentRequest().isPresent();
    }

    @Override
    public void onApplicationEvent(HttpRequestTerminatedEvent event) {
        destroyBeans(event.getSource());
    }

    @NonNull
    @Override
    protected Map> getScopeMap(boolean forCreation) {
        final HttpRequest request = ServerRequestContext.currentRequest().orElse(null);
        if (request != null) {
            //noinspection ConstantConditions
            return getRequestAttributeMap(request, forCreation);
        } else {
            throw new IllegalStateException("No request present");
        }
    }

    @NonNull
    @Override
    protected  CreatedBean doCreate(@NonNull BeanCreationContext creationContext) {
        final HttpRequest request = ServerRequestContext.currentRequest().orElse(null);
        final CreatedBean createdBean = super.doCreate(creationContext);
        final T bean = createdBean.bean();
        if (bean instanceof RequestAware) {
            ((RequestAware) bean).setRequest(request);
        }
        return createdBean;
    }

    /**
     * Destroys the request scoped beans for the given request.
     * @param request The request
     */
    private void destroyBeans(HttpRequest request) {
        ArgumentUtils.requireNonNull("request", request);
        ConcurrentHashMap> requestScopedBeans =
                getRequestAttributeMap(request, false);
        if (requestScopedBeans != null) {
            destroyScope(requestScopedBeans);
        }
    }

    private  ConcurrentHashMap> getRequestAttributeMap(HttpRequest httpRequest, boolean create) {
        MutableConvertibleValues attrs = httpRequest.getAttributes();
        Object o = attrs.getValue(SCOPED_BEANS_ATTRIBUTE);
        if (o instanceof ConcurrentHashMap) {
            return (ConcurrentHashMap>) o;
        }
        if (create) {
            ConcurrentHashMap> scopedBeans = new ConcurrentHashMap<>(5);
            attrs.put(SCOPED_BEANS_ATTRIBUTE, scopedBeans);
            return scopedBeans;
        }
        return null;
    }
}