@Override public <ET extends Event> void push(ET event) { List<Subscriber<ET>> subscribers; synchronized (registeredSubscribers) { if (!registeredSubscribers.containsKey(event.getClass())) return; // Inspection disabled because all inserts in to registeredSubscribers are type insured // due to type erasure, we can not have per-pair types. // noinspection unchecked subscribers = (List<Subscriber<ET>>) new ArrayList(registeredSubscribers.get(event.getClass())); } for (Subscriber<ET> subscriber : subscribers) { boolean txDeterminate = true; for (ListenerFilter filter : subscriber.getFilters()) { // This can only occur if someone f***s something up in an annotation, as listeners should // be typesafe when passed to subscribers // noinspection unchecked txDeterminate = txDeterminate && filter.shouldSend(event); } if (txDeterminate) subscriber.eventReceived(event); } }
@Override public Subscriber<? super Observable<? extends T>> call(Subscriber<? super T> child) { final SerializedSubscriber<T> s = new SerializedSubscriber<T>(child); final CompositeSubscription csub = new CompositeSubscription(); child.add(csub); SourceSubscriber<T> ssub = new SourceSubscriber<T>(maxConcurrency, s, csub); child.setProducer(new MergeMaxConcurrentProducer<T>(ssub)); return ssub; }
@Override public void onNext(T t) { synchronized (this) { if (emitting) { List<T> q = queue; if (q == null) { q = new ArrayList<T>(4); queue = q; } q.add(t); return; } } boolean skipFinal = false; try { child.onNext(t); long r = requested; if (r != Long.MAX_VALUE) { requested = r - 1; } emitLoop(); skipFinal = true; } finally { if (!skipFinal) { synchronized (this) { emitting = false; } } } }
@Override public void subscribe(final Subscriber<? super String> observer) { observer.onSubscribe(EmptySubscription.INSTANCE); t = new Thread( new Runnable() { @Override public void run() { for (String s : valuesToReturn) { if (s == null) { System.out.println("throwing exception"); try { Thread.sleep(100); } catch (Throwable e) { } observer.onError(new NullPointerException()); return; } else { observer.onNext(s); } } System.out.println("subscription complete"); observer.onComplete(); } }); t.start(); }
@Override public void subscribe(Subscriber<? super String> observer) { observer.onSubscribe(EmptySubscription.INSTANCE); boolean errorThrown = false; for (String s : valuesToReturn) { if (s == null) { System.out.println("throwing exception"); observer.onError(new NullPointerException()); errorThrown = true; // purposefully not returning here so it will continue calling onNext // so that we also test that we handle bad sequences like this } else { observer.onNext(s); } } if (!errorThrown) { observer.onComplete(); } }
@Override public void onCompleted() { synchronized (this) { if (emitting) { missedTerminal = true; return; } emitting = true; } child.onCompleted(); }
@Test public void testRequestFromChainedOperator() { TestSubscriber<String> s = new TestSubscriber<>(); Operator<String, String> o = s1 -> new Subscriber<String>() { @Override public void onSubscribe(Subscription a) { s1.onSubscribe(a); } @Override public void onComplete() {} @Override public void onError(Throwable e) {} @Override public void onNext(String t) {} }; s.request(10); Subscriber<? super String> ns = o.apply(s); final AtomicLong r = new AtomicLong(); // set set the producer at the top of the chain (ns) and it should flow through the operator to // the (s) subscriber // and then it should request up with the value set on the final Subscriber (s) ns.onSubscribe( new Subscription() { @Override public void request(long n) { r.set(n); } @Override public void cancel() {} }); assertEquals(10, r.get()); }
@Override public void subscribe(final Subscriber<? super String> observer) { observer.onSubscribe(EmptySubscription.INSTANCE); t = new Thread( new Runnable() { @Override public void run() { observer.onNext("hello"); observer.onComplete(); } }); t.start(); }
void fastPath() { final Iterator<? extends T> a = iterator; final Subscriber<? super T> s = actual; for (; ; ) { if (cancelled) { return; } T t; try { t = a.next(); } catch (Exception ex) { s.onError(ex); return; } if (cancelled) { return; } if (t == null) { s.onError(new NullPointerException("The iterator returned a null value")); return; } s.onNext(t); if (cancelled) { return; } boolean b; try { b = a.hasNext(); } catch (Exception ex) { s.onError(ex); return; } if (cancelled) { return; } if (!b) { s.onComplete(); return; } } }
@Override public void onError(Throwable e) { boolean emit; synchronized (this) { if (emitting) { missedTerminal = e; emit = false; } else { emitting = true; emit = true; } } if (emit) { child.onError(e); } else { hasError = true; } }
@Override public void subscribe(final Subscriber<? super String> observer) { observer.onSubscribe(EmptySubscription.INSTANCE); t = new Thread( new Runnable() { @Override public void run() { try { Thread.sleep(100); } catch (InterruptedException e) { observer.onError(e); } observer.onNext("hello"); observer.onComplete(); } }); t.start(); }
@Override public void onError(Throwable e) { Object[] active; synchronized (subscribers) { active = subscribers.toArray(); subscribers.clear(); } try { s.onError(e); unsubscribe(); } finally { for (Object o : active) { @SuppressWarnings("unchecked") MergeItemSubscriber a = (MergeItemSubscriber) o; a.release(); } } }
/** * Common method to take an Iterator as a source of values. * * @param s * @param it */ static <T> void subscribe(Subscriber<? super T> s, Iterator<? extends T> it) { if (it == null) { EmptySubscription.error(s, new NullPointerException("The iterator is null")); return; } boolean b; try { b = it.hasNext(); } catch (Throwable e) { EmptySubscription.error(s, e); return; } if (!b) { EmptySubscription.complete(s); return; } s.onSubscribe(new PublisherIterableSubscription<>(s, it)); }
void slowPath(long n) { final Iterator<? extends T> a = iterator; final Subscriber<? super T> s = actual; long e = 0L; for (; ; ) { while (e != n) { T t; try { t = a.next(); } catch (Throwable ex) { s.onError(ex); return; } if (cancelled) { return; } if (t == null) { s.onError(new NullPointerException("The iterator returned a null value")); return; } s.onNext(t); if (cancelled) { return; } boolean b; try { b = a.hasNext(); } catch (Throwable ex) { s.onError(ex); return; } if (cancelled) { return; } if (!b) { s.onComplete(); return; } e++; } n = requested; if (n == e) { n = REQUESTED.addAndGet(this, -e); if (n == 0L) { return; } e = 0L; } } }
public void publish(String message) { for (Subscriber subscriber : subscribers) { subscriber.receive(message); } }
@Override public void subscribe(Subscriber<? super String> observer) { observer.onSubscribe(EmptySubscription.INSTANCE); observer.onNext("hello"); observer.onComplete(); }
@Test public void testRequestFromDecoupledOperatorThatRequestsN() { TestSubscriber<String> s = new TestSubscriber<>(); final AtomicLong innerR = new AtomicLong(); Operator<String, String> o = child -> { // we want to decouple the chain so set our own Producer on the child instead of it coming // from the parent child.onSubscribe( new Subscription() { @Override public void request(long n) { innerR.set(n); } @Override public void cancel() {} }); AsyncObserver<String> as = new AsyncObserver<String>() { @Override protected void onStart() { // we request 99 up to the parent request(99); } @Override public void onComplete() {} @Override public void onError(Throwable e) {} @Override public void onNext(String t) {} }; return as; }; s.request(10); Subscriber<? super String> ns = o.apply(s); final AtomicLong r = new AtomicLong(); // set set the producer at the top of the chain (ns) and it should flow through the operator to // the (s) subscriber // and then it should request up with the value set on the final Subscriber (s) ns.onSubscribe( new Subscription() { @Override public void request(long n) { r.set(n); } @Override public void cancel() {} }); assertEquals(99, r.get()); assertEquals(10, innerR.get()); }
void emitLoop() { final Subscriber<? super T> c = child; outer: for (; ; ) { long localRequested; Producer localProducer; Object localTerminal; List<T> q; synchronized (this) { localRequested = missedRequested; localProducer = missedProducer; localTerminal = missedTerminal; q = queue; if (localRequested == 0L && localProducer == null && q == null && localTerminal == null) { emitting = false; return; } missedRequested = 0L; missedProducer = null; queue = null; missedTerminal = null; } boolean empty = q == null || q.isEmpty(); if (localTerminal != null) { if (localTerminal != Boolean.TRUE) { c.onError((Throwable) localTerminal); return; } else if (empty) { c.onCompleted(); return; } } long e = 0; if (q != null) { for (T v : q) { if (c.isUnsubscribed()) { return; } else if (hasError) { continue outer; // if an error has been set, shortcut the loop and act on it } try { c.onNext(v); } catch (Throwable ex) { Exceptions.throwOrReport(ex, c, v); return; } } e += q.size(); } long r = requested; // if requested is max, we don't do any accounting if (r != Long.MAX_VALUE) { // if there were missing requested, add it up if (localRequested != 0L) { long u = r + localRequested; if (u < 0) { u = Long.MAX_VALUE; } r = u; } // if there were emissions and we don't run on max since the last check, subtract if (e != 0L && r != Long.MAX_VALUE) { long u = r - e; if (u < 0) { throw new IllegalStateException("More produced than requested"); } r = u; } requested = r; } if (localProducer != null) { if (localProducer == NULL_PRODUCER) { currentProducer = null; } else { currentProducer = localProducer; if (r != 0L) { localProducer.request(r); } } } else { Producer p = currentProducer; if (p != null && localRequested != 0L) { p.request(localRequested); } } } }
protected void drain() { synchronized (this) { if (emitting) { missedEmitting++; return; } emitting = true; missedEmitting = 0; } final List<SourceSubscriber<T>.MergeItemSubscriber> subs = subscribers; final Subscriber<T> child = s; Object[] active = new Object[subs.size()]; do { long r; outer: while ((r = requested) > 0) { int idx = lastIndex; synchronized (subs) { if (subs.size() == active.length) { active = subs.toArray(active); } else { active = subs.toArray(); } } int resumeIndex = 0; int j = 0; for (Object o : active) { @SuppressWarnings("unchecked") MergeItemSubscriber e = (MergeItemSubscriber) o; if (e.index == idx) { resumeIndex = j; break; } j++; } int sumConsumed = 0; for (int i = 0; i < active.length; i++) { j = (i + resumeIndex) % active.length; @SuppressWarnings("unchecked") final MergeItemSubscriber e = (MergeItemSubscriber) active[j]; final RxRingBuffer b = e.buffer; lastIndex = e.index; if (!e.once && b.peek() == null) { subs.remove(e); synchronized (guard) { this.active--; } csub.remove(e); e.release(); subscribeNext(); WIP.decrementAndGet(this); continue outer; } int consumed = 0; Object v; while (r > 0 && (v = b.poll()) != null) { nl.accept(child, v); if (child.isUnsubscribed()) { return; } r--; consumed++; } if (consumed > 0) { sumConsumed += consumed; REQUESTED.addAndGet(this, -consumed); e.requestMore(consumed); } if (r == 0) { break outer; } } if (sumConsumed == 0) { break; } } if (active.length == 0) { if (wip == 0) { child.onCompleted(); return; } } synchronized (this) { if (missedEmitting == 0) { emitting = false; break; } missedEmitting = 0; } } while (true); }
public void processSubscribe(Request request, ServerTransaction serverTransaction) { logger.debug("Processing SUBSCRIBE in progress "); try { MessageFactory messageFactory = imUA.getMessageFactory(); HeaderFactory headerFactory = imUA.getHeaderFactory(); AddressFactory addressFactory = imUA.getAddressFactory(); Dialog dialog = serverTransaction.getDialog(); // ********** Terminating subscriptions ********** ExpiresHeader expiresHeader = (ExpiresHeader) request.getHeader(ExpiresHeader.NAME); if (expiresHeader != null && expiresHeader.getExpires() == 0) { if (dialog != null) { // Terminating an existing subscription Response response = messageFactory.createResponse(Response.OK, request); serverTransaction.sendResponse(response); IMNotifyProcessing imNotifyProcessing = imUA.getIMNotifyProcessing(); imNotifyProcessing.sendNotify(response, null, dialog); return; } else { // Terminating an non existing subscription Response response = messageFactory.createResponse(Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST, request); serverTransaction.sendResponse(response); return; } } // ********** Non-terminating subscriptions ************ // send a 202 Accepted while waiting for authorization from user Response response = messageFactory.createResponse(Response.ACCEPTED, request); // Tag: ToHeader toHeader = (ToHeader) response.getHeader(ToHeader.NAME); if (toHeader.getTag() == null) toHeader.setTag(new Integer((int) (Math.random() * 10000)).toString()); serverTransaction.sendResponse(response); logger.debug(response.toString()); // We have to ask the user to authorize the guy to be in his buddy // list String presentityURL = IMUtilities.getKey(request, "From"); SipProvider sipProvider = imUA.getSipProvider(); InstantMessagingGUI imGUI = imUA.getInstantMessagingGUI(); boolean authorization = imGUI.getAuthorizationForBuddy(presentityURL); if (authorization) { logger.debug( "DEBUG: SubscribeProcessing, processSubscribe(), " + " Response 202 Accepted sent."); // We have to create or update the subscriber! PresenceManager presenceManager = imUA.getPresenceManager(); String subscriberURL = IMUtilities.getKey(request, "From"); if (dialog != null) presenceManager.addSubscriber(subscriberURL, response, dialog); else { logger.debug( "ERROR, IMSubscribeProcessing, processSubscribe(), the" + " dialog for the SUBSCRIBE we received is null!!! No subscriber added...."); return; } // Let's see if this buddy is in our buddy list // if not let's ask to add him! BuddyList buddyList = imGUI.getBuddyList(); ListenerInstantMessaging listenerIM = imGUI.getListenerInstantMessaging(); if (!buddyList.hasBuddy(subscriberURL)) { // Let's ask: listenerIM.addContact(subscriberURL); } /** ********************** send NOTIFY ************************* */ // We send a NOTIFY for any of our status but offline String localStatus = listenerIM.getLocalStatus(); if (!localStatus.equals("offline")) { IMNotifyProcessing imNotifyProcessing = imUA.getIMNotifyProcessing(); Subscriber subscriber = presenceManager.getSubscriber(subscriberURL); // Response okSent=subscriber.getOkSent(); subscriberURL = subscriber.getSubscriberName(); String contactAddress = imUA.getIMAddress() + ":" + imUA.getIMPort(); String subStatus = listenerIM.getLocalStatus(); String status = null; if (subStatus.equals("offline")) status = "closed"; else status = "open"; String xmlBody = imNotifyProcessing.xmlPidfParser.createXMLBody( status, subStatus, subscriberURL, contactAddress); imNotifyProcessing.sendNotify(response, xmlBody, dialog); } } else { // User did not authorize subscription. Terminate it! logger.debug( "DEBUG, IMSubsribeProcessing, processSubscribe(), " + " Subscription declined!"); logger.debug( "DEBUG, IMSubsribeProcessing, processSubscribe(), " + " Sending a Notify with Subscribe-state=terminated"); IMNotifyProcessing imNotifyProcessing = imUA.getIMNotifyProcessing(); if (dialog != null) { imNotifyProcessing.sendNotify(response, null, dialog); logger.debug( "DEBUG, IMSubsribeProcessing, processSubscribe(), " + " Sending a Notify with Subscribe-state=terminated"); } else { logger.debug( "ERROR, IMSubscribeProcessing, processSubscribe(), the" + " dialog for the SUBSCRIBE we received is null!!! \n" + " No terminating Notify sent"); } imNotifyProcessing.sendNotify(response, null, dialog); } } catch (Exception ex) { ex.printStackTrace(); } }