/** * 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; import java.io.IOException; import java.io.OutputStream; import java.lang.annotation.Annotation; import java.lang.reflect.Type; import java.util.concurrent.atomic.AtomicBoolean; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.ext.MessageBodyWriter; import javax.ws.rs.ext.Provider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import rx.Subscriber; import rx.Subscription; import rx.schedulers.Schedulers; /** * {@link MessageBodyWriter} implementation which handles serialization of HystrixStream * * * @author justinjose28 * */ @Provider public class HystrixStreamingOutputProvider implements MessageBodyWriter<HystrixStream> { private static final Logger LOGGER = LoggerFactory.getLogger(HystrixStreamingOutputProvider.class); @Override public boolean isWriteable(Class<?> t, Type gt, Annotation[] as, MediaType mediaType) { return HystrixStream.class.isAssignableFrom(t); } @Override public long getSize(HystrixStream o, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { return -1; } @Override public void writeTo(HystrixStream o, Class<?> t, Type gt, Annotation[] as, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, final OutputStream entity) throws IOException { Subscription sampleSubscription = null; final AtomicBoolean moreDataWillBeSent = new AtomicBoolean(true); try { sampleSubscription = o.getSampleStream().observeOn(Schedulers.io()).subscribe(new Subscriber<String>() { @Override public void onCompleted() { LOGGER.error("HystrixSampleSseServlet: ({}) received unexpected OnCompleted from sample stream", getClass().getSimpleName()); moreDataWillBeSent.set(false); } @Override public void onError(Throwable e) { moreDataWillBeSent.set(false); } @Override public void onNext(String sampleDataAsString) { if (sampleDataAsString != null) { try { entity.write(("data: " + sampleDataAsString + "\n\n").getBytes()); entity.flush(); } catch (IOException ioe) { moreDataWillBeSent.set(false); } } } }); while (moreDataWillBeSent.get()) { try { Thread.sleep(o.getPausePollerThreadDelayInMs()); } catch (InterruptedException e) { moreDataWillBeSent.set(false); } } } finally { o.getConcurrentConnections().decrementAndGet(); if (sampleSubscription != null && !sampleSubscription.isUnsubscribed()) { sampleSubscription.unsubscribe(); } } } }