@Override
 public Observable<T> call(Observable<T> observable) {
   return observable
       .lift(new Indexed<T>(1L))
       .filter(pair -> pair.getLeft() % 2 == 1)
       .map(pair -> pair.getRight());
 }
Beispiel #2
0
  @Test
  public void testUnsubscribeAfterTake() {
    final Subscription s = mock(Subscription.class);
    TestObservableFunc f = new TestObservableFunc("one", "two", "three");
    Observable<String> w = Observable.create(f);

    @SuppressWarnings("unchecked")
    Observer<String> observer = mock(Observer.class);

    Subscriber<String> subscriber = Subscribers.from(observer);
    subscriber.add(s);

    Observable<String> take = w.lift(new OperatorTake<String>(1));
    take.subscribe(subscriber);

    // wait for the Observable to complete
    try {
      f.t.join();
    } catch (Throwable e) {
      e.printStackTrace();
      fail(e.getMessage());
    }

    System.out.println("TestObservable thread finished");
    verify(observer, times(1)).onNext("one");
    verify(observer, never()).onNext("two");
    verify(observer, never()).onNext("three");
    verify(observer, times(1)).onCompleted();
    verify(s, times(1)).unsubscribe();
    verifyNoMoreInteractions(observer);
  }
  /**
   * Executes the interceptor chain for the passed request and response.
   *
   * @param request Request to be executed.
   * @param response Response to be populated.
   * @param keyEvaluationContext The context for {@link InterceptorKey} evaluation.
   * @return The final result of execution after executing all the inbound and outbound interceptors
   *     and the router.
   */
  public Observable<Void> execute(final I request, final O response, C keyEvaluationContext) {
    final ExecutionContext context = new ExecutionContext(request, keyEvaluationContext);
    InboundInterceptor<I, O> nextIn = context.nextIn(request);
    Observable<Void> startingPoint;

    if (null != nextIn) {
      startingPoint = nextIn.in(request, response);
    } else if (context.invokeRouter()) {
      startingPoint = router.handle(request, response);
    } else {
      return Observable.error(
          new IllegalStateException("No router defined.")); // No router defined.
    }

    return startingPoint.lift(
        new Observable.Operator<Void, Void>() {
          @Override
          public Subscriber<? super Void> call(Subscriber<? super Void> child) {
            SerialSubscription subscription = new SerialSubscription();
            ChainSubscriber chainSubscriber =
                new ChainSubscriber(subscription, context, request, response, child);
            subscription.set(chainSubscriber);
            child.add(subscription);
            return chainSubscriber;
          }
        });
  }
Beispiel #4
0
  /**
   * Rechunks the strings based on a regex pattern and works on infinite stream.
   *
   * <p>resplit(["boo:an", "d:foo"], ":") --> ["boo", "and", "foo"] resplit(["boo:an", "d:foo"],
   * "o") --> ["b", "", ":and:f", "", ""]
   *
   * <p>See {@link Pattern}
   *
   * @param src
   * @param regex
   * @return
   */
  public static Observable<String> split(final Observable<String> src, String regex) {
    final Pattern pattern = Pattern.compile(regex);

    return src.lift(
        new Operator<String, String>() {
          @Override
          public Subscriber<? super String> call(final Subscriber<? super String> o) {
            return new Subscriber<String>(o) {
              private String leftOver = null;

              @Override
              public void onCompleted() {
                output(leftOver);
                if (!o.isUnsubscribed()) o.onCompleted();
              }

              @Override
              public void onError(Throwable e) {
                output(leftOver);
                if (!o.isUnsubscribed()) o.onError(e);
              }

              @Override
              public void onNext(String segment) {
                String[] parts = pattern.split(segment, -1);

                if (leftOver != null) parts[0] = leftOver + parts[0];
                for (int i = 0; i < parts.length - 1; i++) {
                  String part = parts[i];
                  output(part);
                }
                leftOver = parts[parts.length - 1];
              }

              private int emptyPartCount = 0;

              /**
               * when limit == 0 trailing empty parts are not emitted.
               *
               * @param part
               */
              private void output(String part) {
                if (part.isEmpty()) {
                  emptyPartCount++;
                } else {
                  for (; emptyPartCount > 0; emptyPartCount--)
                    if (!o.isUnsubscribed()) o.onNext("");
                  if (!o.isUnsubscribed()) o.onNext(part);
                }
              }
            };
          }
        });
  }
Beispiel #5
0
  @Test
  public void testTake2() {
    Observable<String> w = Observable.from(Arrays.asList("one", "two", "three"));
    Observable<String> take = w.lift(new OperatorTake<String>(1));

    @SuppressWarnings("unchecked")
    Observer<String> observer = mock(Observer.class);
    take.subscribe(observer);
    verify(observer, times(1)).onNext("one");
    verify(observer, never()).onNext("two");
    verify(observer, never()).onNext("three");
    verify(observer, never()).onError(any(Throwable.class));
    verify(observer, times(1)).onCompleted();
  }
Beispiel #6
0
  @Test
  public void testSimpleObject() {
    TestSubscriber<Person> subscriber = new TestSubscriber<>();
    observable.lift(new GsonConverter<Person>()).subscribe(subscriber);

    subscriber.assertNoErrors();
    subscriber.assertTerminalEvent();

    List<Person> persons = subscriber.getOnNextEvents();
    assertEquals(1, persons.size());

    Person person = persons.get(0);
    assertEquals("John", person.name);
    assertEquals(25, person.age);
    assertTrue(person.isDev);
  }
Beispiel #7
0
  @Test
  public void testTakeZeroDoesntLeakError() {
    final AtomicBoolean subscribed = new AtomicBoolean(false);
    final AtomicBoolean unSubscribed = new AtomicBoolean(false);
    Observable<String> source =
        Observable.create(
            new Observable.OnSubscribe<String>() {
              @Override
              public void call(Subscriber<? super String> observer) {
                subscribed.set(true);
                observer.add(
                    new Subscription() {
                      @Override
                      public void unsubscribe() {
                        unSubscribed.set(true);
                      }

                      @Override
                      public boolean isUnsubscribed() {
                        return unSubscribed.get();
                      }
                    });
                observer.onError(new Throwable("test failed"));
              }
            });

    @SuppressWarnings("unchecked")
    Observer<String> observer = mock(Observer.class);

    source.lift(new OperatorTake<String>(0)).subscribe(observer);
    assertTrue("source subscribed", subscribed.get());
    assertTrue("source unsubscribed", unSubscribed.get());

    verify(observer, never()).onNext(anyString());
    // even though onError is called we take(0) so shouldn't see it
    verify(observer, never()).onError(any(Throwable.class));
    verify(observer, times(1)).onCompleted();
    verifyNoMoreInteractions(observer);
  }
Beispiel #8
0
  @Test
  public void testTakeDoesntLeakErrors() {
    Observable<String> source =
        Observable.create(
            new Observable.OnSubscribe<String>() {
              @Override
              public void call(Subscriber<? super String> observer) {
                observer.onNext("one");
                observer.onError(new Throwable("test failed"));
              }
            });

    @SuppressWarnings("unchecked")
    Observer<String> observer = mock(Observer.class);

    source.lift(new OperatorTake<String>(1)).subscribe(observer);

    verify(observer, times(1)).onNext("one");
    // even though onError is called we take(1) so shouldn't see it
    verify(observer, never()).onError(any(Throwable.class));
    verify(observer, times(1)).onCompleted();
    verifyNoMoreInteractions(observer);
  }
Beispiel #9
0
  /**
   * Concatenates the sequence of values by adding a separator between them and emitting the result
   * once the source completes.
   *
   * <p>The conversion from the value type to String is performed via {@link
   * java.lang.String#valueOf(java.lang.Object)} calls.
   *
   * <p>For example:
   *
   * <pre>
   * Observable&lt;Object&gt; source = Observable.from(&quot;a&quot;, 1, &quot;c&quot;);
   * Observable&lt;String&gt; result = join(source, &quot;, &quot;);
   * </pre>
   *
   * will yield a single element equal to "a, 1, c".
   *
   * @param source the source sequence of CharSequence values
   * @param separator the separator to a
   * @return an Observable which emits a single String value having the concatenated values of the
   *     source observable with the separator between elements
   */
  public static <T> Observable<String> join(
      final Observable<T> source, final CharSequence separator) {
    return source.lift(
        new Operator<String, T>() {
          @Override
          public Subscriber<T> call(final Subscriber<? super String> o) {
            return new Subscriber<T>(o) {
              boolean mayAddSeparator;
              StringBuilder b = new StringBuilder();

              @Override
              public void onCompleted() {
                String str = b.toString();
                b = null;
                if (!o.isUnsubscribed()) o.onNext(str);
                if (!o.isUnsubscribed()) o.onCompleted();
              }

              @Override
              public void onError(Throwable e) {
                b = null;
                if (!o.isUnsubscribed()) o.onError(e);
              }

              @Override
              public void onNext(Object t) {
                if (mayAddSeparator) {
                  b.append(separator);
                }
                mayAddSeparator = true;
                b.append(String.valueOf(t));
              }
            };
          }
        });
  }
Beispiel #10
0
  /**
   * Decodes a stream the multibyte chunks into a stream of strings that works on infinite streams
   * and where handles when a multibyte character spans two chunks. This method allows for more
   * control over how malformed and unmappable characters are handled.
   *
   * @param src
   * @param charsetDecoder
   * @return
   */
  public static Observable<String> decode(
      final Observable<byte[]> src, final CharsetDecoder charsetDecoder) {
    return src.lift(
        new Operator<String, byte[]>() {
          @Override
          public Subscriber<? super byte[]> call(final Subscriber<? super String> o) {
            return new Subscriber<byte[]>(o) {
              private ByteBuffer leftOver = null;

              @Override
              public void onCompleted() {
                if (process(null, leftOver, true)) o.onCompleted();
              }

              @Override
              public void onError(Throwable e) {
                if (process(null, leftOver, true)) o.onError(e);
              }

              @Override
              public void onNext(byte[] bytes) {
                process(bytes, leftOver, false);
              }

              public boolean process(byte[] next, ByteBuffer last, boolean endOfInput) {
                ByteBuffer bb;
                if (last != null) {
                  if (next != null) {
                    // merge leftover in front of the next bytes
                    bb = ByteBuffer.allocate(last.remaining() + next.length);
                    bb.put(last);
                    bb.put(next);
                    bb.flip();
                  } else { // next == null
                    bb = last;
                  }
                } else { // last == null
                  if (next != null) {
                    bb = ByteBuffer.wrap(next);
                  } else { // next == null
                    return true;
                  }
                }

                CharBuffer cb =
                    CharBuffer.allocate((int) (bb.limit() * charsetDecoder.averageCharsPerByte()));
                CoderResult cr = charsetDecoder.decode(bb, cb, endOfInput);
                cb.flip();

                if (cr.isError()) {
                  try {
                    cr.throwException();
                  } catch (CharacterCodingException e) {
                    o.onError(e);
                    return false;
                  }
                }

                if (bb.remaining() > 0) {
                  leftOver = bb;
                } else {
                  leftOver = null;
                }

                String string = cb.toString();
                if (!string.isEmpty()) o.onNext(string);

                return true;
              }
            };
          }
        });
  }