Esempio n. 1
0
 /**
  * Receive error for a Observer. Throw the error up the chain and stop processing.
  *
  * @param w
  */
 void error(ZipObserver<T, ?> w, Exception e) {
   if (running.compareAndSet(true, false)) {
     // this thread succeeded in setting running=false so let's propagate the error
     observer.onError(e);
     /* since we receive an error we want to tell everyone to stop */
     stop();
   }
 }
Esempio n. 2
0
 /**
  * Receive notification of a Observer completing its iterations.
  *
  * @param w
  */
 void complete(ZipObserver<T, ?> w) {
   // store that this ZipObserver is completed
   completed.put(w, Boolean.TRUE);
   // if all ZipObservers are completed, we mark the whole thing as completed
   if (completed.size() == observers.size()) {
     if (running.compareAndSet(true, false)) {
       // this thread succeeded in setting running=false so let's propagate the completion
       // mark ourselves as done
       observer.onCompleted();
     }
   }
 }
Esempio n. 3
0
    /**
     * Receive the next value from a Observer.
     *
     * <p>If we have received values from all Observers, trigger the zip function, otherwise store
     * the value and keep waiting.
     *
     * @param w
     * @param arg
     */
    void next(ZipObserver<T, ?> w, Object arg) {
      if (observer == null) {
        throw new RuntimeException("This shouldn't be running if a Observer isn't registered");
      }

      /* if we've been 'unsubscribed' don't process anything further even if the things we're watching keep sending (likely because they are not responding to the unsubscribe call) */
      if (!running.get()) {
        return;
      }

      // store the value we received and below we'll decide if we are to send it to the Observer
      receivedValuesPerObserver.get(w).add(arg);

      // define here so the variable is out of the synchronized scope
      Object[] argsToZip = new Object[observers.size()];

      /* we have to synchronize here despite using concurrent data structures because the compound logic here must all be done atomically */
      synchronized (this) {
        // if all ZipObservers in 'receivedValues' map have a value, invoke the zipFunction
        for (ZipObserver<T, ?> rw : receivedValuesPerObserver.keySet()) {
          if (receivedValuesPerObserver.get(rw).peek() == null) {
            // we have a null meaning the queues aren't all populated so won't do anything
            return;
          }
        }
        // if we get to here this means all the queues have data
        int i = 0;
        for (ZipObserver<T, ?> rw : observers) {
          argsToZip[i++] = receivedValuesPerObserver.get(rw).remove();
        }
      }
      // if we did not return above from the synchronized block we can now invoke the zipFunction
      // with all of the args
      // we do this outside the synchronized block as it is now safe to call this concurrently and
      // don't need to block other threads from calling
      // this 'next' method while another thread finishes calling this zipFunction
      observer.onNext(zipFunction.call(argsToZip));
    }