/** * Copyright 2016 Netflix, Inc. * * 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 * * http://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 com.netflix.hystrix.contrib.metrics.controller; import java.util.concurrent.atomic.AtomicInteger; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.ResponseBuilder; import javax.ws.rs.core.Response.Status; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import rx.Observable; import com.netflix.hystrix.contrib.metrics.HystrixStream; import com.netflix.hystrix.contrib.metrics.HystrixStreamingOutputProvider; /** * @author justinjose28 * */ public abstract class AbstractHystrixStreamController { protected final Observable<String> sampleStream; static final Logger logger = LoggerFactory.getLogger(AbstractHystrixStreamController.class); // wake up occasionally and check that poller is still alive. this value controls how often protected static final int DEFAULT_PAUSE_POLLER_THREAD_DELAY_IN_MS = 500; private final int pausePollerThreadDelayInMs; protected AbstractHystrixStreamController(Observable<String> sampleStream) { this(sampleStream, DEFAULT_PAUSE_POLLER_THREAD_DELAY_IN_MS); } protected AbstractHystrixStreamController(Observable<String> sampleStream, int pausePollerThreadDelayInMs) { this.sampleStream = sampleStream; this.pausePollerThreadDelayInMs = pausePollerThreadDelayInMs; } protected abstract int getMaxNumberConcurrentConnectionsAllowed(); protected abstract AtomicInteger getCurrentConnections(); /** * Maintain an open connection with the client. On initial connection send latest data of each requested event type and subsequently send all changes for each requested event type. * * @return JAX-RS Response - Serialization will be handled by {@link HystrixStreamingOutputProvider} */ protected Response handleRequest() { ResponseBuilder builder = null; /* ensure we aren't allowing more connections than we want */ int numberConnections = getCurrentConnections().get(); int maxNumberConnectionsAllowed = getMaxNumberConcurrentConnectionsAllowed(); // may change at runtime, so look this up for each request if (numberConnections >= maxNumberConnectionsAllowed) { builder = Response.status(Status.SERVICE_UNAVAILABLE).entity("MaxConcurrentConnections reached: " + maxNumberConnectionsAllowed); } else { /* initialize response */ builder = Response.status(Status.OK); builder.header(HttpHeaders.CONTENT_TYPE, "text/event-stream;charset=UTF-8"); builder.header(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate"); builder.header("Pragma", "no-cache"); getCurrentConnections().incrementAndGet(); builder.entity(new HystrixStream(sampleStream, pausePollerThreadDelayInMs, getCurrentConnections())); } return builder.build(); } }