Files should not be executable
[netconf.git] / restconf / restconf-nb-rfc8040 / src / main / java / org / opendaylight / restconf / nb / rfc8040 / streams / websockets / WebSocketFactory.java
1 /*
2  * Copyright © 2019 FRINX s.r.o. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.restconf.nb.rfc8040.streams.websockets;
10
11 import java.util.Optional;
12 import java.util.concurrent.ScheduledExecutorService;
13 import javax.servlet.http.HttpServletResponse;
14 import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
15 import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
16 import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
17 import org.opendaylight.restconf.nb.rfc8040.streams.listeners.BaseListenerInterface;
18 import org.opendaylight.restconf.nb.rfc8040.streams.listeners.ListenersBroker;
19 import org.slf4j.Logger;
20 import org.slf4j.LoggerFactory;
21
22 /**
23  * Factory that is used for creation of new web-sockets based on HTTP/HTTPS upgrade request.
24  */
25 class WebSocketFactory implements WebSocketCreator {
26
27     private static final Logger LOG = LoggerFactory.getLogger(WebSocketFactory.class);
28
29     private final ScheduledExecutorService executorService;
30     private final ListenersBroker listenersBroker = ListenersBroker.getInstance();
31     private final int maximumFragmentLength;
32     private final int heartbeatInterval;
33
34     /**
35      * Creation of the web-socket factory.
36      *
37      * @param executorService       Executor for creation of threads for controlling of web-socket sessions.
38      * @param maximumFragmentLength Maximum web-socket fragment length in number of Unicode code units (characters)
39      *                              (exceeded message length leads to fragmentation of messages).
40      * @param heartbeatInterval     Interval in milliseconds between sending of ping control frames.
41      */
42     WebSocketFactory(final ScheduledExecutorService executorService, final int maximumFragmentLength,
43             final int heartbeatInterval) {
44         this.executorService = executorService;
45         this.maximumFragmentLength = maximumFragmentLength;
46         this.heartbeatInterval = heartbeatInterval;
47     }
48
49     /**
50      * Creation of the new web-socket based on input HTTP/HTTPS upgrade request. Web-socket is created only if the
51      * data listener for input URI can be found (results in status code 101); otherwise status code 404 is set
52      * in upgrade response.
53      *
54      * @param servletUpgradeRequest  Upgrade request.
55      * @param servletUpgradeResponse Upgrade response.
56      * @return Created web-socket instance or {@code null} if the web-socket cannot be created.
57      */
58     @Override
59     public Object createWebSocket(final ServletUpgradeRequest servletUpgradeRequest,
60             final ServletUpgradeResponse servletUpgradeResponse) {
61         final String requestUri = servletUpgradeRequest.getRequestURI().getRawPath();
62         final String streamName = ListenersBroker.createStreamNameFromUri(requestUri);
63
64         final Optional<BaseListenerInterface> listener = listenersBroker.getListenerFor(streamName);
65         if (listener.isPresent()) {
66             LOG.debug("Listener for stream with name {} has been found, web-socket session handler will be created.",
67                     streamName);
68             servletUpgradeResponse.setSuccess(true);
69             servletUpgradeResponse.setStatusCode(HttpServletResponse.SC_SWITCHING_PROTOCOLS);
70             // note: every web-socket manages PING process individually because this approach scales better than sending
71             // of PING frames at once over all web-socket sessions
72             return new WebSocketSessionHandler(executorService, listener.get(), maximumFragmentLength,
73                     heartbeatInterval);
74         } else {
75             LOG.debug("Listener for stream with name {} was not found.", streamName);
76             servletUpgradeResponse.setSuccess(false);
77             servletUpgradeResponse.setStatusCode(HttpServletResponse.SC_NOT_FOUND);
78             return null;
79         }
80     }
81 }