rx.internal.operators.NotificationLite Maven / Gradle / Ivy
Show all versions of rxjava-core Show documentation
/**
* Copyright 2014 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 rx.internal.operators;
import java.io.Serializable;
import rx.Notification.Kind;
import rx.Observer;
/**
* For use in internal operators that need something like materialize and dematerialize wholly within the
* implementation of the operator but don't want to incur the allocation cost of actually creating
* {@link rx.Notification} objects for every {@link Observer#onNext onNext} and
* {@link Observer#onCompleted onCompleted}.
*
* An object is allocated inside {@link #error(Throwable)} to wrap the {@link Throwable} but this shouldn't
* affect performance because exceptions should be exceptionally rare.
*
* It's implemented as a singleton to maintain some semblance of type safety that is completely non-existent.
*
* @param
* @warn type param undescribed
*/
public final class NotificationLite {
private NotificationLite() {
}
@SuppressWarnings("rawtypes")
private static final NotificationLite INSTANCE = new NotificationLite();
/**
* Gets the {@code NotificationLite} singleton.
*
* @return the sole {@code NotificationLite} object
*/
@SuppressWarnings("unchecked")
public static NotificationLite instance() {
return INSTANCE;
}
private static final Object ON_COMPLETED_SENTINEL = new Serializable() {
private static final long serialVersionUID = 1;
public String toString() {
return "Notification=>Completed";
}
};
private static final Object ON_NEXT_NULL_SENTINEL = new Serializable() {
private static final long serialVersionUID = 2;
public String toString() {
return "Notification=>NULL";
}
};
private static class OnErrorSentinel implements Serializable {
private static final long serialVersionUID = 3;
private final Throwable e;
public OnErrorSentinel(Throwable e) {
this.e = e;
}
public String toString() {
return "Notification=>Error:" + e.getMessage();
}
}
/**
* Creates a lite {@code onNext} notification for the value passed in without doing any allocation. Can
* be unwrapped and sent with the {@link #accept} method.
*
* @param t
* the item emitted to {@code onNext}
* @return the item, or a null token representing the item if the item is {@code null}
*/
public Object next(T t) {
if (t == null)
return ON_NEXT_NULL_SENTINEL;
else
return t;
}
/**
* Creates a lite {@code onCompleted} notification without doing any allocation. Can be unwrapped and
* sent with the {@link #accept} method.
*
* @return a completion token
*/
public Object completed() {
return ON_COMPLETED_SENTINEL;
}
/**
* Create a lite {@code onError} notification. This call creates an object to wrap the {@link Throwable},
* but since there should only be one of these, the performance impact should be small. Can be unwrapped and
* sent with the {@link #accept} method.
*
* @param e
* the {@code Throwable} in the {@code onError} notification
* @return an object encapsulating the exception
*/
public Object error(Throwable e) {
return new OnErrorSentinel(e);
}
/**
* Unwraps the lite notification and calls the appropriate method on the {@link Observer}.
*
* @param o
* the {@link Observer} to call {@code onNext}, {@code onCompleted}, or {@code onError}.
* @param n
* the lite notification
* @return {@code true} if {@code n} represents a termination event; {@code false} otherwise
* @throws IllegalArgumentException
* if the notification is null.
* @throws NullPointerException
* if the {@link Observer} is null.
*/
@SuppressWarnings("unchecked")
public boolean accept(Observer super T> o, Object n) {
if (n == ON_COMPLETED_SENTINEL) {
o.onCompleted();
return true;
} else if (n == ON_NEXT_NULL_SENTINEL) {
o.onNext(null);
return false;
} else if (n != null) {
if (n.getClass() == OnErrorSentinel.class) {
o.onError(((OnErrorSentinel) n).e);
return true;
}
o.onNext((T) n);
return false;
} else {
throw new IllegalArgumentException("The lite notification can not be null");
}
}
/**
* Indicates whether or not the lite notification represents an {@code onCompleted} event.
*
* @param n
* the lite notification
* @return {@code true} if {@code n} represents an {@code onCompleted} event; {@code false} otherwise
*/
public boolean isCompleted(Object n) {
return n == ON_COMPLETED_SENTINEL;
}
/**
* Indicates whether or not the lite notification represents an {@code onError} event.
*
* @param n
* the lite notification
* @return {@code true} if {@code n} represents an {@code onError} event; {@code false} otherwise
*/
public boolean isError(Object n) {
return n instanceof OnErrorSentinel;
}
/**
* Indicates which variety a particular lite notification is. If you need something more complex than
* simply calling the right method on an {@link Observer} then you can use this method to get the
* {@link rx.Notification.Kind}.
*
* @param n
* the lite notification
* @throws IllegalArgumentException
* if the notification is null.
* @return the {@link Kind} of lite notification {@code n} is: either {@code Kind.OnCompleted},
* {@code Kind.OnError}, or {@code Kind.OnNext}
*/
public Kind kind(Object n) {
if (n == null)
throw new IllegalArgumentException("The lite notification can not be null");
else if (n == ON_COMPLETED_SENTINEL)
return Kind.OnCompleted;
else if (n instanceof OnErrorSentinel)
return Kind.OnError;
else
// value or ON_NEXT_NULL_SENTINEL but either way it's an OnNext
return Kind.OnNext;
}
/**
* Returns the item corresponding to this {@code OnNext} lite notification. Bad things happen if you pass
* this an {@code OnComplete} or {@code OnError} notification type. For performance reasons, this method
* does not check for this, so you are expected to prevent such a mishap.
*
* @param n
* the lite notification (of type {@code Kind.OnNext})
* @return the unwrapped value, which can be null
*/
@SuppressWarnings("unchecked")
public T getValue(Object n) {
return n == ON_NEXT_NULL_SENTINEL ? null : (T) n;
}
/**
* Returns the {@link Throwable} corresponding to this {@code OnError} lite notification. Bad things happen
* if you pass this an {@code OnComplete} or {@code OnNext} notification type. For performance reasons, this
* method does not check for this, so you are expected to prevent such a mishap.
*
* @param n
* the lite notification (of type {@code Kind.OnError})
* @return the {@link Throwable} wrapped inside {@code n}
*/
public Throwable getError(Object n) {
return ((OnErrorSentinel) n).e;
}
}