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

io.micronaut.websocket.context.DefaultWebSocketBeanRegistry 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.websocket.context;

import io.micronaut.context.BeanContext;
import io.micronaut.context.Qualifier;
import io.micronaut.inject.BeanDefinition;
import io.micronaut.inject.ExecutableMethod;
import io.micronaut.inject.ExecutionHandle;
import io.micronaut.inject.MethodExecutionHandle;
import io.micronaut.inject.qualifiers.Qualifiers;
import io.micronaut.websocket.WebSocketPongMessage;
import io.micronaut.websocket.annotation.OnClose;
import io.micronaut.websocket.annotation.OnError;
import io.micronaut.websocket.annotation.OnMessage;
import io.micronaut.websocket.annotation.OnOpen;
import io.micronaut.websocket.exceptions.WebSocketException;

import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Default implementation of {@link WebSocketBeanRegistry}.
 *
 * @author graemerocher
 * @since 1.0
 */
class DefaultWebSocketBeanRegistry implements WebSocketBeanRegistry {

    private final BeanContext beanContext;
    private final Class stereotype;
    private final Map, WebSocketBean> webSocketBeanMap = new ConcurrentHashMap<>(3);

    /**
     * Default constructor.
     *
     * @param beanContext The bean context
     * @param stereotype Stereotype to use for bean lookup
     */
    DefaultWebSocketBeanRegistry(BeanContext beanContext, Class stereotype) {
        this.beanContext = beanContext;
        this.stereotype = stereotype;
    }

    @Override
    public  WebSocketBean getWebSocket(Class type) {

        WebSocketBean webSocketBean = webSocketBeanMap.get(type);
        if (webSocketBean != null) {
            return webSocketBean;
        } else {

            Qualifier qualifier = Qualifiers.byStereotype(stereotype);
            BeanDefinition beanDefinition = beanContext.getBeanDefinition(type, qualifier);
            T bean = beanContext.getBean(type, qualifier);
            Collection> executableMethods = beanDefinition.getExecutableMethods();
            MethodExecutionHandle onOpen = null;
            MethodExecutionHandle onClose = null;
            MethodExecutionHandle onMessage = null;
            MethodExecutionHandle onPong = null;
            MethodExecutionHandle onError = null;
            for (ExecutableMethod method : executableMethods) {
                if (method.isAnnotationPresent(OnOpen.class)) {
                    onOpen = ExecutionHandle.of(
                        bean,
                        method
                    );
                    continue;
                }

                if (method.isAnnotationPresent(OnClose.class)) {
                    onClose = ExecutionHandle.of(
                        bean,
                        method
                    );
                    continue;
                }

                if (method.isAnnotationPresent(OnError.class)) {
                    onError = ExecutionHandle.of(
                        bean,
                        method
                    );
                    continue;
                }

                if (method.isAnnotationPresent(OnMessage.class)) {
                    if (Arrays.asList(method.getArgumentTypes()).contains(WebSocketPongMessage.class)) {
                        onPong = ExecutionHandle.of(
                            bean,
                            method
                        );
                    } else {
                        onMessage = ExecutionHandle.of(
                            bean,
                            method
                        );
                    }
                }
            }
            if (onMessage == null) {
                throw new WebSocketException("WebSocket handler must specify an @OnMessage handler: " + bean);
            }
            DefaultWebSocketBean newWebSocketBean = new DefaultWebSocketBean<>(bean, beanDefinition, onOpen, onClose, onMessage, onPong, onError);
            if (beanDefinition.isSingleton()) {
                webSocketBeanMap.put(type, newWebSocketBean);
            }
            return newWebSocketBean;
        }
    }

    /**
     * Default web socket impl.
     *
     * @param 
     * @author graemerocher
     */
    private static class DefaultWebSocketBean implements WebSocketBean {
        private final T bean;
        private final BeanDefinition definition;
        private final MethodExecutionHandle onOpen;
        private final MethodExecutionHandle onClose;
        private final MethodExecutionHandle onMessage;
        private final MethodExecutionHandle onPong;
        private final MethodExecutionHandle onError;

        DefaultWebSocketBean(T bean, BeanDefinition definition, MethodExecutionHandle onOpen, MethodExecutionHandle onClose, MethodExecutionHandle onMessage, MethodExecutionHandle onPong, MethodExecutionHandle onError) {
            this.bean = bean;
            this.definition = definition;
            this.onOpen = onOpen;
            this.onClose = onClose;
            this.onMessage = onMessage;
            this.onPong = onPong;
            this.onError = onError;
        }

        @Override
        public BeanDefinition getBeanDefinition() {
            return definition;
        }

        @Override
        public T getTarget() {
            return bean;
        }

        @Override
        public Optional> messageMethod() {
            return Optional.of(onMessage);
        }

        @Override
        public Optional> pongMethod() {
            return Optional.ofNullable(onPong);
        }

        @Override
        public Optional> closeMethod() {
            return Optional.ofNullable(onClose);
        }

        @Override
        public Optional> openMethod() {
            return Optional.ofNullable(onOpen);
        }

        @Override
        public Optional> errorMethod() {
            return Optional.ofNullable(onError);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy