To make death I removed RxJava

This commit is contained in:
huangyuhui
2016-01-26 19:50:26 +08:00
parent 54e14a25da
commit 409fc83819
109 changed files with 197 additions and 10696 deletions

View File

@@ -21,7 +21,6 @@ import org.jackhuang.hellominecraft.utils.functions.Predicate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import rx.Observable;
/**
*
@@ -31,7 +30,9 @@ public final class CollectionUtils {
public static <T> ArrayList<T> map(Collection<T> coll, Predicate<T> p) {
ArrayList<T> newColl = new ArrayList<>();
Observable.from(coll).filter(t -> p.apply(t)).subscribe(t -> newColl.add(t));
for (T t : coll)
if (p.apply(t))
newColl.add(t);
return newColl;
}

View File

@@ -18,7 +18,6 @@
package org.jackhuang.hellominecraft.utils;
import java.util.Map;
import rx.Observable;
/**
*
@@ -50,13 +49,13 @@ public interface IUpdateChecker {
*
* @return the process observable.
*/
Observable process(boolean showMessage);
OverridableSwingWorker<VersionNumber> process(boolean showMessage);
/**
* Get the download links.
*
* @return a JSON, which contains the server response.
*/
Observable<Map<String, String>> requestDownloadLink();
OverridableSwingWorker<Map<String, String>> requestDownloadLink();
}

View File

@@ -29,7 +29,6 @@ import java.net.Proxy;
import java.net.URL;
import java.util.Map;
import org.jackhuang.hellominecraft.utils.system.IOUtils;
import rx.Observable;
/**
*
@@ -158,14 +157,4 @@ public final class NetUtils {
throw new IllegalArgumentException("Could not concatenate given URL with GET arguments!", ex);
}
}
public static Observable<String> getRx(String url) {
return Observable.createWithEmptySubscription(t1 -> {
try {
t1.onNext(get(url));
} catch (Exception e) {
t1.onError(e);
}
});
}
}

View File

@@ -0,0 +1,65 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.utils;
import java.util.ArrayList;
import java.util.List;
import javax.swing.SwingWorker;
import org.jackhuang.hellominecraft.utils.functions.Consumer;
/**
*
* @author huangyuhui
*/
public abstract class OverridableSwingWorker<T> extends SwingWorker<Void, T> {
List<Consumer<T>> processListeners = new ArrayList<>();
List<Runnable> doneListeners = new ArrayList<>();
protected abstract void work() throws Exception;
@Override
protected void done() {
for (Runnable c : doneListeners)
c.run();
}
@Override
protected Void doInBackground() throws Exception {
work();
return null;
}
public OverridableSwingWorker reg(Consumer<T> c) {
processListeners.add(c);
return this;
}
public OverridableSwingWorker regDone(Runnable c) {
doneListeners.add(c);
return this;
}
@Override
protected void process(List<T> chunks) {
for (T t : chunks)
for (Consumer<T> c : processListeners)
c.accept(t);
}
}

View File

@@ -19,7 +19,6 @@ package org.jackhuang.hellominecraft.utils;
import org.jackhuang.hellominecraft.utils.logging.HMCLog;
import java.util.Map;
import rx.Observable;
/**
*
@@ -41,27 +40,26 @@ public final class UpdateChecker implements IUpdateChecker {
VersionNumber value;
@Override
public Observable<VersionNumber> process(boolean showMessage) {
return Observable.createWithEmptySubscription(t -> {
if (value == null) {
try {
versionString = NetUtils.get("http://huangyuhui.duapp.com/info.php?type=" + type);
} catch (Exception e) {
HMCLog.warn("Failed to get update url.", e);
return;
}
value = VersionNumber.check(versionString);
}
public OverridableSwingWorker<VersionNumber> process(boolean showMessage) {
return new OverridableSwingWorker() {
@Override
protected void work() throws Exception {
if (value == null) {
HMCLog.warn("Failed to check update...");
if (showMessage)
MessageBox.Show(C.i18n("update.failed"));
} else if (VersionNumber.isOlder(base, value))
OUT_DATED = true;
if (OUT_DATED)
t.onNext(value);
});
if (value == null) {
versionString = NetUtils.get("http://huangyuhui.duapp.com/info.php?type=" + type);
value = VersionNumber.check(versionString);
}
if (value == null) {
HMCLog.warn("Failed to check update...");
if (showMessage)
MessageBox.Show(C.i18n("update.failed"));
} else if (VersionNumber.isOlder(base, value))
OUT_DATED = true;
if (OUT_DATED)
publish(value);
}
};
}
@Override
@@ -70,16 +68,19 @@ public final class UpdateChecker implements IUpdateChecker {
}
@Override
public synchronized Observable<Map<String, String>> requestDownloadLink() {
return Observable.createWithEmptySubscription(t -> {
if (download_link == null)
try {
download_link = C.gson.fromJson(NetUtils.get("http://huangyuhui.duapp.com/update_link.php?type=" + type), Map.class);
} catch (Exception e) {
HMCLog.warn("Failed to get update link.", e);
}
t.onNext(download_link);
});
public synchronized OverridableSwingWorker<Map<String, String>> requestDownloadLink() {
return new OverridableSwingWorker() {
@Override
protected void work() throws Exception {
if (download_link == null)
try {
download_link = C.gson.fromJson(NetUtils.get("http://huangyuhui.duapp.com/update_link.php?type=" + type), Map.class);
} catch (Exception e) {
HMCLog.warn("Failed to get update link.", e);
}
publish(download_link);
}
};
}
public final EventHandler<VersionNumber> outdated = new EventHandler<>(this);

View File

@@ -1,45 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.utils.tasks;
import rx.Observable;
/**
*
* @author huangyuhui
*/
public class TaskObservable<T> extends TaskInfo {
private final Observable<T> r;
public TaskObservable(String info, Observable<T> r) {
super(info);
this.r = r;
}
public TaskObservable(Observable<T> r) {
this("TaskObservable", r);
}
@Override
public void executeTask() {
r.subscribe(t -> {
});
}
}

View File

@@ -1,156 +0,0 @@
/**
* Copyright 2013 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;
/**
* An object representing a notification sent to an {@link Observable}.
*
* For the Microsoft Rx equivalent see:
* http://msdn.microsoft.com/en-us/library/hh229462(v=vs.103).aspx
*/
public class Notification<T> {
private final Kind kind;
private final Exception exception;
private final T value;
/**
* A constructor used to represent an onNext notification.
*
* @param value The data passed to the onNext method.
*/
public Notification(T value) {
this.value = value;
this.exception = null;
this.kind = Kind.OnNext;
}
/**
* A constructor used to represent an onError notification.
*
* @param exception The exception passed to the onError notification.
*/
public Notification(Exception exception) {
this.exception = exception;
this.value = null;
this.kind = Kind.OnError;
}
/**
* A constructor used to represent an onCompleted notification.
*/
public Notification() {
this.exception = null;
this.value = null;
this.kind = Kind.OnCompleted;
}
/**
* Retrieves the exception associated with an onError notification.
*
* @return The exception associated with an onError notification.
*/
public Exception getException() {
return exception;
}
/**
* Retrieves the data associated with an onNext notification.
*
* @return The data associated with an onNext notification.
*/
public T getValue() {
return value;
}
/**
* Retrieves a value indicating whether this notification has a value.
*
* @return a value indicating whether this notification has a value.
*/
public boolean hasValue() {
return isOnNext() && value != null;
}
/**
* Retrieves a value indicating whether this notification has an exception.
*
* @return a value indicating whether this notification has an exception.
*/
public boolean hasException() {
return isOnError() && exception != null;
}
/**
* The kind of notification: OnNext, OnError, OnCompleted
*
* @return
*/
public Kind getKind() {
return kind;
}
public boolean isOnError() {
return getKind() == Kind.OnError;
}
public boolean isOnCompleted() {
return getKind() == Kind.OnCompleted;
}
public boolean isOnNext() {
return getKind() == Kind.OnNext;
}
public static enum Kind {
OnNext, OnError, OnCompleted
}
@Override
public String toString() {
StringBuilder str = new StringBuilder("[").append(super.toString()).append(" ").append(getKind());
if (hasValue())
str.append(" ").append(getValue());
if (hasException())
str.append(" ").append(getException().getMessage());
str.append("]");
return str.toString();
}
@Override
public int hashCode() {
int hash = getKind().hashCode();
if (hasValue())
hash = hash * 31 + getValue().hashCode();
if (hasException())
hash = hash * 31 + getException().hashCode();
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null)
return false;
if (this == obj)
return true;
if (obj.getClass() != getClass())
return false;
Notification<?> notification = (Notification<?>) obj;
if (notification.getKind() != getKind() || hasValue() && !getValue().equals(notification.getValue()))
return false;
return !(hasException() && !getException().equals(notification.getException()));
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,68 +0,0 @@
/**
* Copyright 2013 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;
/**
* Provides a mechanism for receiving push-based notifications.
* <p>
* After an Observer calls an {@link Observable}'s
* <code>Observable.subscribe</code> method, the {@link Observable} calls the
* Observer's <code>onNext</code> method to provide notifications. A
* well-behaved {@link Observable} will call an Observer's
* <code>onCompleted</code> closure exactly once or the Observer's
* <code>onError</code> closure exactly once.
* <p>
* For more information see the
* <a href="https://github.com/Netflix/RxJava/wiki/Observable">RxJava Wiki</a>
*
* @param <T>
*/
public interface Observer<T> {
/**
* Notifies the Observer that the {@link Observable} has finished sending
* push-based notifications.
* <p>
* The {@link Observable} will not call this closure if it calls
* <code>onError</code>.
*/
public void onCompleted();
/**
* Notifies the Observer that the {@link Observable} has experienced an
* error condition.
* <p>
* If the {@link Observable} calls this closure, it will not thereafter call
* <code>onNext</code> or <code>onCompleted</code>.
*
* @param e
*/
public void onError(Exception e);
/**
* Provides the Observer with new data.
* <p>
* The {@link Observable} calls this closure 1 or more times, unless it
* calls <code>onError</code> in which case this closure may never be
* called.
* <p>
* The {@link Observable} will not call this closure again after it calls
* either <code>onCompleted</code> or <code>onError</code>.
*
* @param args
*/
public void onNext(T args);
}

View File

@@ -1,69 +0,0 @@
/**
* Copyright 2013 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;
import java.util.concurrent.TimeUnit;
import rx.util.functions.Action0;
import rx.util.functions.Func0;
/**
* Represents an object that schedules units of work.
*/
public interface Scheduler {
/**
* Schedules a cancelable action to be executed.
*
* @param action action
*
* @return a subscription to be able to unsubscribe from action.
*/
Subscription schedule(Func0<Subscription> action);
/**
* Schedules an action to be executed.
*
* @param action action
*
* @return a subscription to be able to unsubscribe from action.
*/
Subscription schedule(Action0 action);
/**
* Schedules an action to be executed in dueTime.
*
* @param action action
*
* @return a subscription to be able to unsubscribe from action.
*/
Subscription schedule(Action0 action, long dueTime, TimeUnit unit);
/**
* Schedules a cancelable action to be executed in dueTime.
*
* @param action action
*
* @return a subscription to be able to unsubscribe from action.
*/
Subscription schedule(Func0<Subscription> action, long dueTime, TimeUnit unit);
/**
* Returns the scheduler's notion of current time.
*/
long now();
}

View File

@@ -1,38 +0,0 @@
/**
* Copyright 2013 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;
import rx.subscriptions.Subscriptions;
/**
* Subscription returns from {@link Observable#subscribe(Observer)} to allow
* unsubscribing.
* <p>
* See utilities in {@link Subscriptions} and implementations in the
* {@link rx.subscriptions} package.
*/
public interface Subscription {
/**
* Stop receiving notifications on the {@link Observer} that was registered
* when this Subscription was received.
* <p>
* This allows unregistering an {@link Observer} before it has finished
* receiving all events (ie. before onCompleted is called).
*/
public void unsubscribe();
}

View File

@@ -1,53 +0,0 @@
/**
* Copyright 2013 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.concurrency;
import java.util.concurrent.TimeUnit;
import rx.Scheduler;
import rx.Subscription;
import rx.subscriptions.Subscriptions;
import rx.util.functions.Action0;
import rx.util.functions.Func0;
/*
* package
*/
abstract class AbstractScheduler implements Scheduler {
@Override
public Subscription schedule(Action0 action) {
return schedule(asFunc0(action));
}
@Override
public Subscription schedule(Action0 action, long dueTime, TimeUnit unit) {
return schedule(asFunc0(action), dueTime, unit);
}
@Override
public long now() {
return System.nanoTime();
}
private static Func0<Subscription> asFunc0(final Action0 action) {
return () -> {
action.call();
return Subscriptions.empty();
};
}
}

View File

@@ -1,72 +0,0 @@
/**
* Copyright 2013 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.concurrency;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.TimeUnit;
import rx.Subscription;
import rx.util.functions.Func0;
/**
* Schedules work on the current thread but does not execute immediately. Work
* is put in a queue and executed after the current unit of work is completed.
*/
public class CurrentThreadScheduler extends AbstractScheduler {
private static final CurrentThreadScheduler INSTANCE = new CurrentThreadScheduler();
public static CurrentThreadScheduler getInstance() {
return INSTANCE;
}
private static final ThreadLocal<Queue<DiscardableAction>> QUEUE = new ThreadLocal<>();
private CurrentThreadScheduler() {
}
@Override
public Subscription schedule(Func0<Subscription> action) {
DiscardableAction discardableAction = new DiscardableAction(action);
enqueue(discardableAction);
return discardableAction;
}
@Override
public Subscription schedule(Func0<Subscription> action, long dueTime, TimeUnit unit) {
return schedule(new SleepingAction(action, this, dueTime, unit));
}
private void enqueue(DiscardableAction action) {
Queue<DiscardableAction> queue = QUEUE.get();
boolean exec = queue == null;
if (exec) {
queue = new LinkedList<>();
QUEUE.set(queue);
}
queue.add(action);
if (exec) {
while (!queue.isEmpty())
queue.poll().call();
QUEUE.set(null);
}
}
}

View File

@@ -1,58 +0,0 @@
/**
* Copyright 2013 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.concurrency;
import java.util.concurrent.atomic.AtomicBoolean;
import rx.Subscription;
import rx.util.AtomicObservableSubscription;
import rx.util.functions.Func0;
/**
* Combines standard {@link Subscription#unsubscribe()} functionality with
* ability to skip execution if an unsubscribe occurs before the {@link #call()}
* method is invoked.
*/
/*
* package
*/
class DiscardableAction implements Func0<Subscription>, Subscription {
private final Func0<Subscription> underlying;
private final AtomicObservableSubscription wrapper = new AtomicObservableSubscription();
private final AtomicBoolean ready = new AtomicBoolean(true);
public DiscardableAction(Func0<Subscription> underlying) {
this.underlying = underlying;
}
@Override
public Subscription call() {
if (ready.compareAndSet(true, false)) {
Subscription subscription = underlying.call();
wrapper.wrap(subscription);
return subscription;
}
return wrapper;
}
@Override
public void unsubscribe() {
ready.set(false);
wrapper.unsubscribe();
}
}

View File

@@ -1,51 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package rx.concurrency;
import java.awt.EventQueue;
import java.util.concurrent.TimeUnit;
import rx.Subscription;
import rx.util.functions.Func0;
/**
*
* @author huangyuhui
*/
public class EventQueueScheduler extends AbstractScheduler {
private static final EventQueueScheduler INSTANCE = new EventQueueScheduler();
public static EventQueueScheduler getInstance() {
return INSTANCE;
}
@Override
public Subscription schedule(Func0<Subscription> action) {
final DiscardableAction discardableAction = new DiscardableAction(action);
EventQueue.invokeLater(discardableAction::call);
return discardableAction;
}
@Override
public Subscription schedule(Func0<Subscription> action, long dueTime, TimeUnit unit) {
return schedule(new SleepingAction(action, this, dueTime, unit));
}
}

View File

@@ -1,106 +0,0 @@
/**
* Copyright 2013 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.concurrency;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import rx.Scheduler;
import rx.Subscription;
import rx.util.functions.Func0;
/**
* A {@link Scheduler} implementation that uses an {@link Executor} or
* {@link ScheduledExecutorService} implementation.
* <p>
* Note that if an {@link Executor} implementation is used instead of
* {@link ScheduledExecutorService} then a system-wide Timer will be used to
* handle delayed events.
*/
public class ExecutorScheduler extends AbstractScheduler {
private final Executor executor;
/**
* Setup a ScheduledExecutorService that we can use if someone provides an
* Executor instead of ScheduledExecutorService.
*/
private final static ScheduledExecutorService SYSTEM_SCHEDULED_EXECUTOR;
static {
int count = Runtime.getRuntime().availableProcessors();
if (count > 8)
count = count / 2;
// we don't need more than 8 to handle just scheduling and doing no work
if (count > 8)
count = 8;
SYSTEM_SCHEDULED_EXECUTOR = Executors.newScheduledThreadPool(count, new ThreadFactory() {
final AtomicInteger counter = new AtomicInteger();
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, "RxScheduledExecutorPool-" + counter.incrementAndGet());
t.setDaemon(true);
return t;
}
});
}
public ExecutorScheduler(Executor executor) {
this.executor = executor;
}
public ExecutorScheduler(ScheduledExecutorService executor) {
this.executor = executor;
}
@Override
public Subscription schedule(Func0<Subscription> action, long dueTime, TimeUnit unit) {
final DiscardableAction discardableAction = new DiscardableAction(action);
if (executor instanceof ScheduledExecutorService)
((ScheduledExecutorService) executor).schedule(discardableAction::call, dueTime, unit);
else if (dueTime == 0)
// no delay so put on the thread-pool right now
return (schedule(action));
else
// there is a delay and this isn't a ScheduledExecutorService so we'll use a system-wide ScheduledExecutorService
// to handle the scheduling and once it's ready then execute on this Executor
SYSTEM_SCHEDULED_EXECUTOR.schedule(() -> {
// now execute on the real Executor
executor.execute(discardableAction::call);
}, dueTime, unit);
return discardableAction;
}
@Override
public Subscription schedule(Func0<Subscription> action) {
final DiscardableAction discardableAction = new DiscardableAction(action);
executor.execute(discardableAction::call);
return discardableAction;
}
}

View File

@@ -1,47 +0,0 @@
/**
* Copyright 2013 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.concurrency;
import java.util.concurrent.TimeUnit;
import rx.Subscription;
import rx.util.functions.Func0;
/**
* Executes work immediately on the current thread.
*/
public final class ImmediateScheduler extends AbstractScheduler {
private static final ImmediateScheduler INSTANCE = new ImmediateScheduler();
public static ImmediateScheduler getInstance() {
return INSTANCE;
}
private ImmediateScheduler() {
}
@Override
public Subscription schedule(Func0<Subscription> action) {
return action.call();
}
@Override
public Subscription schedule(Func0<Subscription> action, long dueTime, TimeUnit unit) {
return schedule(new SleepingAction(action, this, dueTime, unit));
}
}

View File

@@ -1,50 +0,0 @@
/**
* Copyright 2013 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.concurrency;
import java.util.concurrent.TimeUnit;
import rx.Subscription;
import rx.util.functions.Func0;
/**
* Schedules work on a new thread.
*/
public class NewThreadScheduler extends AbstractScheduler {
private static final NewThreadScheduler INSTANCE = new NewThreadScheduler();
public static NewThreadScheduler getInstance() {
return INSTANCE;
}
@Override
public Subscription schedule(Func0<Subscription> action) {
final DiscardableAction discardableAction = new DiscardableAction(action);
Thread t = new Thread(discardableAction::call, "RxNewThreadScheduler");
t.start();
return discardableAction;
}
@Override
public Subscription schedule(Func0<Subscription> action, long dueTime, TimeUnit unit) {
return schedule(new SleepingAction(action, this, dueTime, unit));
}
}

View File

@@ -1,162 +0,0 @@
/**
* Copyright 2013 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.concurrency;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import rx.Scheduler;
/**
* Static factory methods for creating Schedulers.
*/
public class Schedulers {
private static final ScheduledExecutorService COMPUTATION_EXECUTOR = createComputationExecutor();
private static final Executor IO_EXECUTOR = createIOExecutor();
private Schedulers() {
}
/**
* {@link Scheduler} that executes work immediately on the current thread.
*
* @return {@link ImmediateScheduler} instance
*/
public static Scheduler immediate() {
return ImmediateScheduler.getInstance();
}
/**
* {@link Scheduler} that queues work on the current thread to be executed
* after the current work completes.
*
* @return {@link CurrentThreadScheduler} instance
*/
public static Scheduler currentThread() {
return CurrentThreadScheduler.getInstance();
}
/**
* {@link Scheduler} that creates a new {@link Thread} for each unit of
* work.
*
* @return {@link NewThreadScheduler} instance
*/
public static Scheduler newThread() {
return NewThreadScheduler.getInstance();
}
/**
* {@link Scheduler} that queues work on the EventQueue thread to be
* executed on the Swing UI Thread.
*
* @return {@link NewThreadScheduler} instance
*/
public static Scheduler eventQueue() {
return EventQueueScheduler.getInstance();
}
/**
* {@link Scheduler} that queues work on an {@link Executor}.
* <p>
* Note that this does not support scheduled actions with a delay.
*
* @return {@link ExecutorScheduler} instance
*/
public static Scheduler executor(Executor executor) {
return new ExecutorScheduler(executor);
}
/**
* {@link Scheduler} that queues work on an
* {@link ScheduledExecutorService}.
*
* @return {@link ExecutorScheduler} instance
*/
public static Scheduler executor(ScheduledExecutorService executor) {
return new ExecutorScheduler(executor);
}
/**
* {@link Scheduler} intended for computational work.
* <p>
* The implementation is backed by a {@link ScheduledExecutorService}
* thread-pool sized to the number of CPU cores.
* <p>
* This can be used for event-loops, processing callbacks and other
* computational work.
* <p>
* Do not perform IO-bound work on this scheduler. Use
* {@link #threadPoolForComputation()} instead.
*
* @return {@link ExecutorScheduler} for computation-bound work.
*/
public static Scheduler threadPoolForComputation() {
return executor(COMPUTATION_EXECUTOR);
}
/**
* {@link Scheduler} intended for IO-bound work.
* <p>
* The implementation is backed by an {@link Executor} thread-pool that will
* grow as needed.
* <p>
* This can be used for asynchronously performing blocking IO.
* <p>
* Do not perform computational work on this scheduler. Use
* {@link #threadPoolForComputation()} instead.
*
* @return {@link ExecutorScheduler} for IO-bound work.
*/
public static Scheduler threadPoolForIO() {
return executor(IO_EXECUTOR);
}
private static ScheduledExecutorService createComputationExecutor() {
int cores = Runtime.getRuntime().availableProcessors();
return Executors.newScheduledThreadPool(cores, new ThreadFactory() {
final AtomicInteger counter = new AtomicInteger();
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, "RxComputationThreadPool-" + counter.incrementAndGet());
t.setDaemon(true);
return t;
}
});
}
private static Executor createIOExecutor() {
Executor result = Executors.newCachedThreadPool(new ThreadFactory() {
final AtomicLong counter = new AtomicLong();
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, "RxIOThreadPool-" + counter.incrementAndGet());
t.setDaemon(true);
return t;
}
});
return result;
}
}

View File

@@ -1,52 +0,0 @@
/**
* Copyright 2013 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.concurrency;
import java.util.concurrent.TimeUnit;
import rx.Scheduler;
import rx.Subscription;
import rx.util.functions.Func0;
/*
* package
*/
class SleepingAction implements Func0<Subscription> {
private final Func0<Subscription> underlying;
private final Scheduler scheduler;
private final long execTime;
public SleepingAction(Func0<Subscription> underlying, Scheduler scheduler, long timespan, TimeUnit timeUnit) {
this.underlying = underlying;
this.scheduler = scheduler;
this.execTime = scheduler.now() + timeUnit.toMillis(timespan);
}
@Override
public Subscription call() {
if (execTime < scheduler.now())
try {
Thread.sleep(scheduler.now() - execTime);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}
return underlying.call();
}
}

View File

@@ -1,46 +0,0 @@
/**
* Copyright 2013 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.observables;
import rx.Observable;
import rx.Observer;
import rx.Subscription;
import rx.util.functions.Func1;
/**
* An {@link Observable} that has been grouped by a key whose value can be
* obtained using {@link #getKey()}
* <p>
*
* @see {@link Observable#groupBy(Observable, Func1)}
*
* @param <K>
* @param <T>
*/
public class GroupedObservable<K, T> extends Observable<T> {
private final K key;
public GroupedObservable(K key, Func1<Observer<T>, Subscription> onSubscribe) {
super(onSubscribe);
this.key = key;
}
public K getKey() {
return key;
}
}

View File

@@ -1,60 +0,0 @@
package rx.operators;
import rx.Observable;
import rx.Observer;
import rx.Subscription;
import rx.util.AtomicObservableSubscription;
import rx.util.functions.Func1;
import java.util.concurrent.atomic.AtomicBoolean;
public class OperationAll {
public static <T> Func1<Observer<Boolean>, Subscription> all(Observable<T> sequence, Func1<T, Boolean> predicate) {
return new AllObservable<>(sequence, predicate);
}
private static class AllObservable<T> implements Func1<Observer<Boolean>, Subscription> {
private final Observable<T> sequence;
private final Func1<T, Boolean> predicate;
private final AtomicBoolean status = new AtomicBoolean(true);
private final AtomicObservableSubscription subscription = new AtomicObservableSubscription();
private AllObservable(Observable<T> sequence, Func1<T, Boolean> predicate) {
this.sequence = sequence;
this.predicate = predicate;
}
@Override
public Subscription call(final Observer<Boolean> observer) {
return subscription.wrap(sequence.subscribe(new Observer<T>() {
@Override
public void onCompleted() {
if (status.get()) {
observer.onNext(true);
observer.onCompleted();
}
}
@Override
public void onError(Exception e) {
observer.onError(e);
}
@Override
public void onNext(T args) {
boolean result = predicate.call(args);
boolean changed = status.compareAndSet(true, result);
if (changed && !result) {
observer.onNext(false);
observer.onCompleted();
subscription.unsubscribe();
}
}
}));
}
}
}

View File

@@ -1,293 +0,0 @@
/**
* Copyright 2013 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.operators;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import rx.Observable;
import rx.Observer;
import rx.Subscription;
import rx.util.functions.Func1;
import rx.util.functions.Func2;
import rx.util.functions.Func3;
import rx.util.functions.Func4;
import rx.util.functions.FuncN;
import rx.util.functions.Functions;
public class OperationCombineLatest {
/**
* Combines the two given observables, emitting an event containing an
* aggregation of the latest values of each of the source observables each
* time an event is received from one of the source observables, where the
* aggregation is defined by the given function.
*
* @param w0 The first source observable.
* @param w1 The second source observable.
* @param combineLatestFunction The aggregation function used to combine the
* source observable values.
*
* @return A function from an observer to a subscription. This can be used
* to create an observable from.
*/
public static <T0, T1, R> Func1<Observer<R>, Subscription> combineLatest(Observable<T0> w0, Observable<T1> w1, Func2<T0, T1, R> combineLatestFunction) {
Aggregator<R> a = new Aggregator<>(Functions.fromFunc(combineLatestFunction));
a.addObserver(new CombineObserver<R, T0>(a, w0));
a.addObserver(new CombineObserver<R, T1>(a, w1));
return a;
}
/**
* @see #combineLatest(Observable w0, Observable w1, Func2
* combineLatestFunction)
*/
public static <T0, T1, T2, R> Func1<Observer<R>, Subscription> combineLatest(Observable<T0> w0, Observable<T1> w1, Observable<T2> w2, Func3<T0, T1, T2, R> combineLatestFunction) {
Aggregator<R> a = new Aggregator<>(Functions.fromFunc(combineLatestFunction));
a.addObserver(new CombineObserver<R, T0>(a, w0));
a.addObserver(new CombineObserver<R, T1>(a, w1));
a.addObserver(new CombineObserver<R, T2>(a, w2));
return a;
}
/**
* @see #combineLatest(Observable w0, Observable w1, Func2
* combineLatestFunction)
*/
public static <T0, T1, T2, T3, R> Func1<Observer<R>, Subscription> combineLatest(Observable<T0> w0, Observable<T1> w1, Observable<T2> w2, Observable<T3> w3, Func4<T0, T1, T2, T3, R> combineLatestFunction) {
Aggregator<R> a = new Aggregator<>(Functions.fromFunc(combineLatestFunction));
a.addObserver(new CombineObserver<R, T0>(a, w0));
a.addObserver(new CombineObserver<R, T1>(a, w1));
a.addObserver(new CombineObserver<R, T2>(a, w2));
a.addObserver(new CombineObserver<R, T3>(a, w3));
return a;
}
private static class CombineObserver<R, T> implements Observer<T> {
final Observable<T> w;
final Aggregator<R> a;
private Subscription subscription;
public CombineObserver(Aggregator<R> a, Observable<T> w) {
this.a = a;
this.w = w;
}
public synchronized void startWatching() {
if (subscription != null)
throw new RuntimeException("This should only be called once.");
subscription = w.subscribe(this);
}
@Override
public void onCompleted() {
a.complete(this);
}
@Override
public void onError(Exception e) {
a.error(e);
}
@Override
public void onNext(T args) {
a.next(this, args);
}
}
/**
* Receive notifications from each of the observables we are reducing and
* execute the combineLatestFunction whenever we have received an event from
* one of the observables, as soon as each Observable has received at least
* one event.
*/
private static class Aggregator<R> implements Func1<Observer<R>, Subscription> {
private Observer<R> observer;
private final FuncN<R> combineLatestFunction;
private final AtomicBoolean running = new AtomicBoolean(true);
// used as an internal lock for handling the latest values and the completed state of each observer
private final Object lockObject = new Object();
/**
* Store when an observer completes.
* <p>
* Note that access to this set MUST BE SYNCHRONIZED via 'lockObject'
* above.
*
*/
private final Set<CombineObserver<R, ?>> completed = new HashSet<>();
/**
* The latest value from each observer
* <p>
* Note that access to this set MUST BE SYNCHRONIZED via 'lockObject'
* above.
*
*/
private final Map<CombineObserver<R, ?>, Object> latestValue = new HashMap<>();
/**
* Whether each observer has a latest value at all.
* <p>
* Note that access to this set MUST BE SYNCHRONIZED via 'lockObject'
* above.
*
*/
private final Set<CombineObserver<R, ?>> hasLatestValue = new HashSet<>();
/**
* Ordered list of observers to combine. No synchronization is necessary
* as these can not be added or changed asynchronously.
*/
private final List<CombineObserver<R, ?>> observers = new LinkedList<>();
public Aggregator(FuncN<R> combineLatestFunction) {
this.combineLatestFunction = combineLatestFunction;
}
/**
* Receive notification of a Observer starting (meaning we should
* require it for aggregation)
*
* @param w The observer to add.
*/
<T> void addObserver(CombineObserver<R, T> w) {
observers.add(w);
}
/**
* Receive notification of a Observer completing its iterations.
*
* @param w The observer that has completed.
*/
<T> void complete(CombineObserver<R, T> w) {
synchronized (lockObject) {
// store that this CombineLatestObserver is completed
completed.add(w);
// if all CombineObservers are completed, we mark the whole thing as completed
if (completed.size() == observers.size())
if (running.get()) {
// mark ourselves as done
observer.onCompleted();
// just to ensure we stop processing in case we receive more onNext/complete/error calls after this
running.set(false);
}
}
}
/**
* Receive error for a Observer. Throw the error up the chain and stop
* processing.
*/
void error(Exception e) {
observer.onError(e);
/*
* tell all observers to unsubscribe since we had an error
*/
stop();
}
/**
* Receive the next value from an observer.
* <p>
* If we have received values from all observers, trigger the
* combineLatest function, otherwise store the value and keep waiting.
*
* @param w
* @param arg
*/
<T> void next(CombineObserver<R, T> w, T arg) {
if (observer == null)
throw new RuntimeException("This shouldn't be running if an 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;
// define here so the variable is out of the synchronized scope
Object[] argsToCombineLatest = new Object[observers.size()];
// we synchronize everything that touches latest values
synchronized (lockObject) {
// remember this as the latest value for this observer
latestValue.put(w, arg);
// remember that this observer now has a latest value set
hasLatestValue.add(w);
// if all observers in the 'observers' list have a value, invoke the combineLatestFunction
for (CombineObserver<R, ?> rw : observers)
if (!hasLatestValue.contains(rw))
// we don't have a value yet for each observer to combine, so we don't have a combined value yet either
return;
// if we get to here this means all the queues have data
int i = 0;
for (CombineObserver<R, ?> _w : observers)
argsToCombineLatest[i++] = latestValue.get(_w);
}
// if we did not return above from the synchronized block we can now invoke the combineLatestFunction 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 combineLatestFunction
observer.onNext(combineLatestFunction.call(argsToCombineLatest));
}
@Override
public Subscription call(Observer<R> observer) {
if (this.observer != null)
throw new IllegalStateException("Only one Observer can subscribe to this Observable.");
this.observer = observer;
/*
* start the observers
*/
for (CombineObserver<R, ?> rw : observers)
rw.startWatching();
return new Subscription() {
@Override
public void unsubscribe() {
stop();
}
};
}
private void stop() {
/*
* tell ourselves to stop processing onNext events
*/
running.set(false);
/*
* propogate to all observers to unsubscribe
*/
for (CombineObserver<R, ?> rw : observers)
if (rw.subscription != null)
rw.subscription.unsubscribe();
}
}
}

View File

@@ -1,130 +0,0 @@
/**
* Copyright 2013 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.operators;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import rx.Observable;
import rx.Observer;
import rx.Subscription;
import rx.util.AtomicObservableSubscription;
import rx.util.functions.Action1;
import rx.util.functions.Func1;
public final class OperationConcat {
/**
* Combine the observable sequences from the list of Observables into one
* observable sequence without any transformation.
*
* @param sequences An observable sequence of elements to project.
*
* @return An observable sequence whose elements are the result of combining
* the output from the list of Observables.
*/
public static <T> Func1<Observer<T>, Subscription> concat(final Observable<T>... sequences) {
return new Func1<Observer<T>, Subscription>() {
@Override
public Subscription call(Observer<T> observer) {
return new Concat<T>(sequences).call(observer);
}
};
}
public static <T> Func1<Observer<T>, Subscription> concat(final List<Observable<T>> sequences) {
@SuppressWarnings("unchecked")
Observable<T>[] o = sequences.toArray((Observable<T>[]) Array.newInstance(Observable.class, sequences.size()));
return concat(o);
}
public static <T> Func1<Observer<T>, Subscription> concat(final Observable<Observable<T>> sequences) {
final List<Observable<T>> list = new ArrayList<Observable<T>>();
sequences.toList().subscribe(new Action1<List<Observable<T>>>() {
@Override
public void call(List<Observable<T>> t1) {
list.addAll(t1);
}
});
return concat(list);
}
private static class Concat<T> implements Func1<Observer<T>, Subscription> {
private final Observable<T>[] sequences;
private int num = 0;
private int count = 0;
private Subscription s;
Concat(final Observable<T>... sequences) {
this.sequences = sequences;
this.num = sequences.length - 1;
}
private final AtomicObservableSubscription Subscription = new AtomicObservableSubscription();
private final Subscription actualSubscription = new Subscription() {
@Override
public void unsubscribe() {
if (null != s)
s.unsubscribe();
}
};
public Subscription call(Observer<T> observer) {
s = sequences[count].subscribe(new ConcatObserver(observer));
return Subscription.wrap(actualSubscription);
}
private class ConcatObserver implements Observer<T> {
private final Observer<T> observer;
ConcatObserver(Observer<T> observer) {
this.observer = observer;
}
@Override
public void onCompleted() {
if (num == count)
observer.onCompleted();
else {
count++;
s = sequences[count].subscribe(this);
}
}
@Override
public void onError(Exception e) {
observer.onError(e);
}
@Override
public void onNext(T args) {
observer.onNext(args);
}
}
}
}

View File

@@ -1,30 +0,0 @@
/**
* Copyright 2013 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.operators;
import rx.Observable;
import rx.Observer;
import rx.Subscription;
import rx.util.functions.Func0;
import rx.util.functions.Func1;
public final class OperationDefer {
public static <T> Func1<Observer<T>, Subscription> defer(final Func0<Observable<T>> observableFactory) {
return observableFactory.call()::subscribe;
}
}

View File

@@ -1,84 +0,0 @@
/**
* Copyright 2013 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.operators;
import rx.Notification;
import rx.Observable;
import rx.Observer;
import rx.Subscription;
import rx.util.functions.Func1;
/**
* Dematerializes the explicit notification values of an observable sequence as
* implicit notifications. See
* http://msdn.microsoft.com/en-us/library/hh229047(v=vs.103).aspx for the
* Microsoft Rx equivalent.
*/
public final class OperationDematerialize {
/**
* Dematerializes the explicit notification values of an observable sequence
* as implicit notifications.
*
* @param sequence An observable sequence containing explicit notification
* values which have to be turned into implicit notifications.
*
* @return An observable sequence exhibiting the behavior corresponding to
* the source sequence's notification values.
*
* @see http://msdn.microsoft.com/en-us/library/hh229047(v=vs.103).aspx
*/
public static <T> Func1<Observer<T>, Subscription> dematerialize(final Observable<Notification<T>> sequence) {
return new DematerializeObservable<>(sequence);
}
private static class DematerializeObservable<T> implements Func1<Observer<T>, Subscription> {
private final Observable<Notification<T>> sequence;
public DematerializeObservable(Observable<Notification<T>> sequence) {
this.sequence = sequence;
}
@Override
public Subscription call(final Observer<T> observer) {
return sequence.subscribe(new Observer<Notification<T>>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Exception e) {
}
@Override
public void onNext(Notification<T> value) {
switch (value.getKind()) {
case OnNext:
observer.onNext(value.getValue());
break;
case OnError:
observer.onError(value.getException());
break;
case OnCompleted:
observer.onCompleted();
break;
}
}
});
}
}
}

View File

@@ -1,69 +0,0 @@
/**
* Copyright 2013 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.operators;
import rx.Observable;
import rx.Observer;
import rx.Subscription;
import rx.util.AtomicObservableSubscription;
import rx.util.functions.Func1;
public final class OperationFilter<T> {
public static <T> Func1<Observer<T>, Subscription> filter(Observable<T> that, Func1<T, Boolean> predicate) {
return new Filter<>(that, predicate);
}
private static class Filter<T> implements Func1<Observer<T>, Subscription> {
private final Observable<T> that;
private final Func1<T, Boolean> predicate;
private final AtomicObservableSubscription subscription = new AtomicObservableSubscription();
public Filter(Observable<T> that, Func1<T, Boolean> predicate) {
this.that = that;
this.predicate = predicate;
}
@Override
public Subscription call(final Observer<T> observer) {
return subscription.wrap(that.subscribe(new Observer<T>() {
@Override
public void onNext(T value) {
try {
if (predicate.call(value))
observer.onNext(value);
} catch (Exception ex) {
observer.onError(ex);
// this will work if the sequence is asynchronous, it will have no effect on a synchronous observable
subscription.unsubscribe();
}
}
@Override
public void onError(Exception ex) {
observer.onError(ex);
}
@Override
public void onCompleted() {
observer.onCompleted();
}
}));
}
}
}

View File

@@ -1,98 +0,0 @@
/**
* Copyright 2013 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.operators;
import rx.Observable;
import rx.Observer;
import rx.Subscription;
import rx.util.functions.Action0;
import rx.util.functions.Func1;
public final class OperationFinally {
/**
* Call a given action when a sequence completes (with or without an
* exception). The returned observable is exactly as threadsafe as the
* source observable.
* <p/>
* Note that "finally" is a Java reserved word and cannot be an identifier,
* so we use "finallyDo".
*
* @param sequence An observable sequence of elements
* @param action An action to be taken when the sequence is complete or
* throws an exception
*
* @return An observable sequence with the same elements as the input. After
* the last element is consumed (and {@link Observer#onCompleted} has been
* called), or after an exception is thrown (and {@link Observer#onError}
* has been called), the given action will be called.
*
* @see
* <a href="http://msdn.microsoft.com/en-us/library/hh212133(v=vs.103).aspx">MSDN
* Observable.Finally method</a>
*/
public static <T> Func1<Observer<T>, Subscription> finallyDo(final Observable<T> sequence, final Action0 action) {
return new Finally<>(sequence, action)::call;
}
private static class Finally<T> implements Func1<Observer<T>, Subscription> {
private final Observable<T> sequence;
private final Action0 finalAction;
Finally(final Observable<T> sequence, Action0 finalAction) {
this.sequence = sequence;
this.finalAction = finalAction;
}
@Override
public Subscription call(Observer<T> observer) {
return sequence.subscribe(new FinallyObserver(observer));
}
private class FinallyObserver implements Observer<T> {
private final Observer<T> observer;
FinallyObserver(Observer<T> observer) {
this.observer = observer;
}
@Override
public void onCompleted() {
try {
observer.onCompleted();
} finally {
finalAction.call();
}
}
@Override
public void onError(Exception e) {
try {
observer.onError(e);
} finally {
finalAction.call();
}
}
@Override
public void onNext(T args) {
observer.onNext(args);
}
}
}
}

View File

@@ -1,123 +0,0 @@
/**
* Copyright 2013 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.operators;
import rx.Observable;
import rx.Observer;
import rx.Subscription;
import rx.util.functions.Func1;
public final class OperationMap {
/**
* Accepts a sequence and a transformation function. Returns a sequence that
* is the result of applying the transformation function to each item in the
* sequence.
*
* @param sequence the input sequence.
* @param func a function to apply to each item in the sequence.
* @param <T> the type of the input sequence.
* @param <R> the type of the output sequence.
*
* @return a sequence that is the result of applying the transformation
* function to each item in the input sequence.
*/
public static <T, R> Func1<Observer<R>, Subscription> map(Observable<T> sequence, Func1<T, R> func) {
return new MapObservable<>(sequence, func);
}
/**
* Accepts a sequence of observable sequences and a transformation function.
* Returns a flattened sequence that is the result of applying the
* transformation function to each item in the sequence of each observable
* sequence.
* <p>
* The closure should return an Observable which will then be merged.
*
* @param sequence the input sequence.
* @param func a function to apply to each item in the sequence.
* @param <T> the type of the input sequence.
* @param <R> the type of the output sequence.
*
* @return a sequence that is the result of applying the transformation
* function to each item in the input sequence.
*/
public static <T, R> Func1<Observer<R>, Subscription> mapMany(Observable<T> sequence, Func1<T, Observable<R>> func) {
return OperationMerge.merge(Observable.create(map(sequence, func)));
}
/**
* An observable sequence that is the result of applying a transformation to
* each item in an input sequence.
*
* @param <T> the type of the input sequence.
* @param <R> the type of the output sequence.
*/
private static class MapObservable<T, R> implements Func1<Observer<R>, Subscription> {
public MapObservable(Observable<T> sequence, Func1<T, R> func) {
this.sequence = sequence;
this.func = func;
}
private final Observable<T> sequence;
private final Func1<T, R> func;
@Override
public Subscription call(Observer<R> observer) {
return sequence.subscribe(new MapObserver<>(observer, func));
}
}
/**
* An observer that applies a transformation function to each item and
* forwards the result to an inner observer.
*
* @param <T> the type of the observer items.
* @param <R> the type of the inner observer items.
*/
private static class MapObserver<T, R> implements Observer<T> {
public MapObserver(Observer<R> observer, Func1<T, R> func) {
this.observer = observer;
this.func = func;
}
Observer<R> observer;
Func1<T, R> func;
@Override
public void onNext(T value) {
try {
observer.onNext(func.call(value));
} catch (Exception ex) {
observer.onError(ex);
}
}
@Override
public void onError(Exception ex) {
observer.onError(ex);
}
@Override
public void onCompleted() {
observer.onCompleted();
}
}
}

View File

@@ -1,85 +0,0 @@
/**
* Copyright 2013 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.operators;
import rx.Notification;
import rx.Observable;
import rx.Observer;
import rx.Subscription;
import rx.util.functions.Func1;
/**
* Materializes the implicit notifications of an observable sequence as explicit
* notification values.
* <p>
* In other words, converts a sequence of OnNext, OnError and OnCompleted events
* into a sequence of ObservableNotifications containing the OnNext, OnError and
* OnCompleted values.
* <p>
* See http://msdn.microsoft.com/en-us/library/hh229453(v=VS.103).aspx for the
* Microsoft Rx equivalent.
*/
public final class OperationMaterialize {
/**
* Materializes the implicit notifications of an observable sequence as
* explicit notification values.
*
* @param sequence An observable sequence of elements to project.
*
* @return An observable sequence whose elements are the result of
* materializing the notifications of the given sequence.
*
* @see http://msdn.microsoft.com/en-us/library/hh229453(v=VS.103).aspx
*/
public static <T> Func1<Observer<Notification<T>>, Subscription> materialize(final Observable<T> sequence) {
return new MaterializeObservable<>(sequence);
}
private static class MaterializeObservable<T> implements Func1<Observer<Notification<T>>, Subscription> {
private final Observable<T> sequence;
public MaterializeObservable(Observable<T> sequence) {
this.sequence = sequence;
}
@Override
public Subscription call(final Observer<Notification<T>> observer) {
return sequence.subscribe(new Observer<T>() {
@Override
public void onCompleted() {
observer.onNext(new Notification<>());
observer.onCompleted();
}
@Override
public void onError(Exception e) {
observer.onNext(new Notification<>(e));
observer.onCompleted();
}
@Override
public void onNext(T value) {
observer.onNext(new Notification<>(value));
}
});
}
}
}

View File

@@ -1,261 +0,0 @@
/**
* Copyright 2013 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.operators;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import rx.Observable;
import rx.Observer;
import rx.Subscription;
import rx.util.AtomicObservableSubscription;
import rx.util.SynchronizedObserver;
import rx.util.functions.Func1;
public final class OperationMerge {
/**
* Flattens the observable sequences from the list of Observables into one
* observable sequence without any transformation.
*
* @param source An observable sequence of elements to project.
*
* @return An observable sequence whose elements are the result of
* flattening the output from the list of Observables.
*
* @see http://msdn.microsoft.com/en-us/library/hh229099(v=vs.103).aspx
*/
public static <T> Func1<Observer<T>, Subscription> merge(final Observable<Observable<T>> source) {
// wrap in a Func so that if a chain is built up, then asynchronously subscribed to twice we will have 2 instances of Take<T> rather than 1 handing both, which is not thread-safe.
return new MergeObservable<T>(source)::call;
}
public static <T> Func1<Observer<T>, Subscription> merge(final Observable<T>... sequences) {
return merge(Arrays.asList(sequences));
}
public static <T> Func1<Observer<T>, Subscription> merge(final List<Observable<T>> sequences) {
return merge(Observable.create(new Func1<Observer<Observable<T>>, Subscription>() {
private volatile boolean unsubscribed = false;
@Override
public Subscription call(Observer<Observable<T>> observer) {
for (Observable<T> o : sequences)
if (!unsubscribed)
observer.onNext(o);
else
// break out of the loop if we are unsubscribed
break;
if (!unsubscribed)
observer.onCompleted();
return () -> {
unsubscribed = true;
};
}
}));
}
/**
* This class is NOT thread-safe if invoked and referenced multiple times.
* In other words, don't subscribe to it multiple times from different
* threads.
* <p>
* It IS thread-safe from within it while receiving onNext events from
* multiple threads.
* <p>
* This should all be fine as long as it's kept as a private class and a new
* instance created from static factory method above.
* <p>
* Note how the take() factory method above protects us from a single
* instance being exposed with the Observable wrapper handling the subscribe
* flow.
*
* @param <T>
*/
private static final class MergeObservable<T> implements Func1<Observer<T>, Subscription> {
private final Observable<Observable<T>> sequences;
private final MergeSubscription ourSubscription = new MergeSubscription();
private final AtomicBoolean stopped = new AtomicBoolean(false);
private volatile boolean parentCompleted = false;
private final ConcurrentHashMap<ChildObserver, ChildObserver> childObservers = new ConcurrentHashMap<>();
private final ConcurrentHashMap<ChildObserver, Subscription> childSubscriptions = new ConcurrentHashMap<>();
private MergeObservable(Observable<Observable<T>> sequences) {
this.sequences = sequences;
}
@Override
public Subscription call(Observer<T> actualObserver) {
/**
* We must synchronize a merge because we subscribe to multiple
* sequences in parallel that will each be emitting.
* <p>
* The calls from each sequence must be serialized.
* <p>
* Bug report: https://github.com/Netflix/RxJava/issues/200
*/
AtomicObservableSubscription subscription = new AtomicObservableSubscription(ourSubscription);
SynchronizedObserver<T> synchronizedObserver = new SynchronizedObserver<>(actualObserver, subscription);
/**
* Subscribe to the parent Observable to get to the children
* Observables
*/
sequences.subscribe(new ParentObserver(synchronizedObserver));
/*
* return our subscription to allow unsubscribing
*/
return subscription;
}
/**
* Manage the internal subscription with a thread-safe means of
* stopping/unsubscribing so we don't unsubscribe twice.
* <p>
* Also has the stop() method returning a boolean so callers know if
* their thread "won" and should perform further actions.
*/
private class MergeSubscription implements Subscription {
@Override
public void unsubscribe() {
stop();
}
public boolean stop() {
// try setting to false unless another thread beat us
boolean didSet = stopped.compareAndSet(false, true);
if (didSet) {
// this thread won the race to stop, so unsubscribe from the actualSubscription
for (Subscription _s : childSubscriptions.values())
_s.unsubscribe();
return true;
} else
// another thread beat us
return false;
}
}
/**
* Subscribe to the top level Observable to receive the sequence of
* Observable<T> children.
*
* @param <T>
*/
private class ParentObserver implements Observer<Observable<T>> {
private final Observer<T> actualObserver;
public ParentObserver(Observer<T> actualObserver) {
this.actualObserver = actualObserver;
}
@Override
public void onCompleted() {
parentCompleted = true;
// this *can* occur before the children are done, so if it does we won't send onCompleted
// but will let the child worry about it
// if however this completes and there are no children processing, then we will send onCompleted
if (childObservers.isEmpty())
if (!stopped.get())
if (ourSubscription.stop())
actualObserver.onCompleted();
}
@Override
public void onError(Exception e) {
actualObserver.onError(e);
}
@Override
public void onNext(Observable<T> childObservable) {
if (stopped.get())
// we won't act on any further items
return;
if (childObservable == null)
throw new IllegalArgumentException("Observable<T> can not be null.");
/**
* For each child Observable we receive we'll subscribe with a
* separate Observer that will each then forward their sequences
* to the actualObserver.
* <p>
* We use separate child Observers for each sequence to simplify
* the onComplete/onError handling so each sequence has its own
* lifecycle.
*/
ChildObserver _w = new ChildObserver(actualObserver);
childObservers.put(_w, _w);
Subscription _subscription = childObservable.subscribe(_w);
// remember this Observer and the subscription from it
childSubscriptions.put(_w, _subscription);
}
}
/**
* Subscribe to each child Observable<T> and forward their sequence of
* data to the actualObserver
*
*/
private class ChildObserver implements Observer<T> {
private final Observer<T> actualObserver;
public ChildObserver(Observer<T> actualObserver) {
this.actualObserver = actualObserver;
}
@Override
public void onCompleted() {
// remove self from map of Observers
childObservers.remove(this);
// if there are now 0 Observers left, so if the parent is also completed we send the onComplete to the actualObserver
// if the parent is not complete that means there is another sequence (and child Observer) to come
if (!stopped.get())
if (childObservers.isEmpty() && parentCompleted)
if (ourSubscription.stop())
// this thread 'won' the race to unsubscribe/stop so let's send onCompleted
actualObserver.onCompleted();
}
@Override
public void onError(Exception e) {
if (!stopped.get())
if (ourSubscription.stop())
// this thread 'won' the race to unsubscribe/stop so let's send the error
actualObserver.onError(e);
}
@Override
public void onNext(T args) {
// in case the Observable is poorly behaved and doesn't listen to the unsubscribe request
// we'll ignore anything that comes in after we've unsubscribed
if (!stopped.get())
actualObserver.onNext(args);
}
}
}
}

View File

@@ -1,337 +0,0 @@
/**
* Copyright 2013 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.operators;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import rx.Observable;
import rx.Observer;
import rx.Subscription;
import rx.util.CompositeException;
import rx.util.functions.Func1;
/**
* Same functionality as OperationMerge except that onError events will be
* skipped so that all onNext calls are passed on until all sequences finish
* with onComplete or onError, and then the first onError received (if any) will
* be passed on.
* <p>
* This allows retrieving all successful onNext calls without being blocked by
* an onError early in a sequence.
* <p>
* NOTE: If this is used on an infinite stream it will never call onError and
* effectively will swallow errors.
*/
public final class OperationMergeDelayError {
/**
* Flattens the observable sequences from the list of Observables into one
* observable sequence without any transformation and delays any onError
* calls until after all sequences have called onError or onComplete so as
* to allow all successful onNext calls to be received.
*
* @param source An observable sequence of elements to project.
*
* @return An observable sequence whose elements are the result of
* flattening the output from the list of Observables.
*
* @see http://msdn.microsoft.com/en-us/library/hh229099(v=vs.103).aspx
*/
public static <T> Func1<Observer<T>, Subscription> mergeDelayError(final Observable<Observable<T>> sequences) {
// wrap in a Func so that if a chain is built up, then asynchronously subscribed to twice we will have 2 instances of Take<T> rather than 1 handing both, which is not thread-safe.
return new Func1<Observer<T>, Subscription>() {
@Override
public Subscription call(Observer<T> observer) {
return new MergeDelayErrorObservable<T>(sequences).call(observer);
}
};
}
public static <T> Func1<Observer<T>, Subscription> mergeDelayError(final Observable<T>... sequences) {
return mergeDelayError(Observable.create(new Func1<Observer<Observable<T>>, Subscription>() {
private volatile boolean unsubscribed = false;
@Override
public Subscription call(Observer<Observable<T>> observer) {
for (Observable<T> o : sequences)
if (!unsubscribed)
observer.onNext(o);
else
// break out of the loop if we are unsubscribed
break;
if (!unsubscribed)
observer.onCompleted();
return new Subscription() {
@Override
public void unsubscribe() {
unsubscribed = true;
}
};
}
}));
}
public static <T> Func1<Observer<T>, Subscription> mergeDelayError(final List<Observable<T>> sequences) {
return mergeDelayError(Observable.create(new Func1<Observer<Observable<T>>, Subscription>() {
private volatile boolean unsubscribed = false;
@Override
public Subscription call(Observer<Observable<T>> observer) {
for (Observable<T> o : sequences)
if (!unsubscribed)
observer.onNext(o);
else
// break out of the loop if we are unsubscribed
break;
if (!unsubscribed)
observer.onCompleted();
return new Subscription() {
@Override
public void unsubscribe() {
unsubscribed = true;
}
};
}
}));
}
/**
* This class is NOT thread-safe if invoked and referenced multiple times.
* In other words, don't subscribe to it multiple times from different
* threads.
* <p>
* It IS thread-safe from within it while receiving onNext events from
* multiple threads.
* <p>
* This should all be fine as long as it's kept as a private class and a new
* instance created from static factory method above.
* <p>
* Note how the take() factory method above protects us from a single
* instance being exposed with the Observable wrapper handling the subscribe
* flow.
*
* @param <T>
*/
private static final class MergeDelayErrorObservable<T> implements Func1<Observer<T>, Subscription> {
private final Observable<Observable<T>> sequences;
private final MergeSubscription ourSubscription = new MergeSubscription();
private AtomicBoolean stopped = new AtomicBoolean(false);
private volatile boolean parentCompleted = false;
private final ConcurrentHashMap<ChildObserver, ChildObserver> childObservers = new ConcurrentHashMap<ChildObserver, ChildObserver>();
private final ConcurrentHashMap<ChildObserver, Subscription> childSubscriptions = new ConcurrentHashMap<ChildObserver, Subscription>();
// onErrors we received that will be delayed until everything is completed and then sent
private ConcurrentLinkedQueue<Exception> onErrorReceived = new ConcurrentLinkedQueue<Exception>();
private MergeDelayErrorObservable(Observable<Observable<T>> sequences) {
this.sequences = sequences;
}
public Subscription call(Observer<T> actualObserver) {
/**
* Subscribe to the parent Observable to get to the children
* Observables
*/
sequences.subscribe(new ParentObserver(actualObserver));
/*
* return our subscription to allow unsubscribing
*/
return ourSubscription;
}
/**
* Manage the internal subscription with a thread-safe means of
* stopping/unsubscribing so we don't unsubscribe twice.
* <p>
* Also has the stop() method returning a boolean so callers know if
* their thread "won" and should perform further actions.
*/
private class MergeSubscription implements Subscription {
@Override
public void unsubscribe() {
stop();
}
public boolean stop() {
// try setting to false unless another thread beat us
boolean didSet = stopped.compareAndSet(false, true);
if (didSet) {
// this thread won the race to stop, so unsubscribe from the actualSubscription
for (Subscription _s : childSubscriptions.values())
_s.unsubscribe();
return true;
} else
// another thread beat us
return false;
}
}
/**
* Subscribe to the top level Observable to receive the sequence of
* Observable<T> children.
*
* @param <T>
*/
private class ParentObserver implements Observer<Observable<T>> {
private final Observer<T> actualObserver;
public ParentObserver(Observer<T> actualObserver) {
this.actualObserver = actualObserver;
}
@Override
public void onCompleted() {
parentCompleted = true;
// this *can* occur before the children are done, so if it does we won't send onCompleted
// but will let the child worry about it
// if however this completes and there are no children processing, then we will send onCompleted
if (childObservers.size() == 0)
if (!stopped.get())
if (ourSubscription.stop())
if (onErrorReceived.size() == 1)
// an onError was received from 1 ChildObserver so we now send it as a delayed error
actualObserver.onError(onErrorReceived.peek());
else if (onErrorReceived.size() > 1)
// an onError was received from more than 1 ChildObserver so we now send it as a delayed error
actualObserver.onError(new CompositeException(onErrorReceived));
else
// no delayed error so send onCompleted
actualObserver.onCompleted();
}
@Override
public void onError(Exception e) {
actualObserver.onError(e);
}
@Override
public void onNext(Observable<T> childObservable) {
if (stopped.get())
// we won't act on any further items
return;
if (childObservable == null)
throw new IllegalArgumentException("Observable<T> can not be null.");
/**
* For each child Observable we receive we'll subscribe with a
* separate Observer that will each then forward their sequences
* to the actualObserver.
* <p>
* We use separate child Observers for each sequence to simplify
* the onComplete/onError handling so each sequence has its own
* lifecycle.
*/
ChildObserver _w = new ChildObserver(actualObserver);
childObservers.put(_w, _w);
Subscription _subscription = childObservable.subscribe(_w);
// remember this Observer and the subscription from it
childSubscriptions.put(_w, _subscription);
}
}
/**
* Subscribe to each child Observable<T> and forward their sequence of
* data to the actualObserver
*
*/
private class ChildObserver implements Observer<T> {
private final Observer<T> actualObserver;
private volatile boolean finished = false;
public ChildObserver(Observer<T> actualObserver) {
this.actualObserver = actualObserver;
}
@Override
public void onCompleted() {
// remove self from map of Observers
childObservers.remove(this);
// if there are now 0 Observers left, so if the parent is also completed we send the onComplete to the actualObserver
// if the parent is not complete that means there is another sequence (and child Observer) to come
if (!stopped.get())
finishObserver();
}
@Override
public void onError(Exception e) {
if (!stopped.get()) {
onErrorReceived.add(e);
// mark this ChildObserver as done
childObservers.remove(this);
// but do NOT forward to actualObserver as we want other ChildObservers to continue until completion
// and we'll delay the sending of onError until all others are done
// we mark finished==true as a safety to ensure that if further calls to onNext occur we ignore them
finished = true;
// check for whether the parent is completed and if so then perform the 'finishing' actions
finishObserver();
}
}
/**
* onComplete and onError when called need to check for the parent
* being complete and if so send the onCompleted or onError to the
* actualObserver.
* <p>
* This does NOT get invoked if synchronous execution occurs, but
* will when asynchronously executing.
* <p>
* TestCase testErrorDelayed4WithThreading specifically tests this
* use case.
*/
private void finishObserver() {
if (childObservers.size() == 0 && parentCompleted)
if (ourSubscription.stop())
// this thread 'won' the race to unsubscribe/stop so let's send onError or onCompleted
if (onErrorReceived.size() == 1)
// an onError was received from 1 ChildObserver so we now send it as a delayed error
actualObserver.onError(onErrorReceived.peek());
else if (onErrorReceived.size() > 1)
// an onError was received from more than 1 ChildObserver so we now send it as a delayed error
actualObserver.onError(new CompositeException(onErrorReceived));
else
// no delayed error so send onCompleted
actualObserver.onCompleted();
}
@Override
public void onNext(T args) {
// in case the Observable is poorly behaved and doesn't listen to the unsubscribe request
// we'll ignore anything that comes in after we've unsubscribed or an onError has been received and delayed
if (!stopped.get() && !finished)
actualObserver.onNext(args);
}
}
}
}

View File

@@ -1,106 +0,0 @@
/**
* Copyright 2013 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.operators;
import java.util.Iterator;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import rx.Observable;
import rx.Observer;
import rx.util.Exceptions;
/**
* Samples the most recent value in an observable sequence.
*/
public final class OperationMostRecent {
public static <T> Iterable<T> mostRecent(final Observable<T> source, T initialValue) {
MostRecentObserver<T> mostRecentObserver = new MostRecentObserver<>(initialValue);
MostRecentIterator<T> nextIterator = new MostRecentIterator<>(mostRecentObserver);
source.subscribe(mostRecentObserver);
return () -> nextIterator;
}
private static class MostRecentIterator<T> implements Iterator<T> {
private final MostRecentObserver<T> observer;
private MostRecentIterator(MostRecentObserver<T> observer) {
this.observer = observer;
}
@Override
public boolean hasNext() {
return !observer.isCompleted();
}
@Override
public T next() {
if (observer.getException() != null)
throw Exceptions.propagate(observer.getException());
return observer.getRecentValue();
}
@Override
public void remove() {
throw new UnsupportedOperationException("Read only iterator");
}
}
private static class MostRecentObserver<T> implements Observer<T> {
private final AtomicBoolean completed = new AtomicBoolean(false);
private final AtomicReference<T> value;
private final AtomicReference<Exception> exception = new AtomicReference<>();
private MostRecentObserver(T value) {
this.value = new AtomicReference<>(value);
}
@Override
public void onCompleted() {
completed.set(true);
}
@Override
public void onError(Exception e) {
exception.set(e);
}
@Override
public void onNext(T args) {
value.set(args);
}
public boolean isCompleted() {
return completed.get();
}
public Exception getException() {
return exception.get();
}
public T getRecentValue() {
return value.get();
}
}
}

View File

@@ -1,143 +0,0 @@
/**
* Copyright 2013 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.operators;
import java.util.Iterator;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import rx.Notification;
import rx.Observable;
import rx.Observer;
import rx.util.Exceptions;
/**
* Samples the next value (blocking without buffering) from in an observable
* sequence.
*/
public final class OperationNext {
public static <T> Iterable<T> next(final Observable<T> items) {
NextObserver<T> nextObserver = new NextObserver<>();
final NextIterator<T> nextIterator = new NextIterator<>(nextObserver);
items.materialize().subscribe(nextObserver);
return () -> nextIterator;
}
private static class NextIterator<T> implements Iterator<T> {
private final NextObserver<T> observer;
private NextIterator(NextObserver<T> observer) {
this.observer = observer;
}
@Override
public boolean hasNext() {
return !observer.isCompleted(false);
}
@Override
public T next() {
if (observer.isCompleted(true))
throw new IllegalStateException("Observable is completed");
observer.await();
try {
return observer.takeNext();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw Exceptions.propagate(e);
}
}
@Override
public void remove() {
throw new UnsupportedOperationException("Read only iterator");
}
}
private static class NextObserver<T> implements Observer<Notification<T>> {
private final BlockingQueue<Notification<T>> buf = new ArrayBlockingQueue<>(1);
private final AtomicBoolean waiting = new AtomicBoolean(false);
@Override
public void onCompleted() {
// ignore
}
@Override
public void onError(Exception e) {
// ignore
}
@Override
public void onNext(Notification<T> args) {
if (waiting.getAndSet(false) || !args.isOnNext()) {
Notification<T> toOffer = args;
while (!buf.offer(toOffer)) {
Notification<T> concurrentItem = buf.poll();
// in case if we won race condition with onComplete/onError method
if (!concurrentItem.isOnNext())
toOffer = concurrentItem;
}
}
}
public void await() {
waiting.set(true);
}
public boolean isCompleted(boolean rethrowExceptionIfExists) {
Notification<T> lastItem = buf.peek();
if (lastItem == null)
return false;
if (lastItem.isOnError())
if (rethrowExceptionIfExists)
throw Exceptions.propagate(lastItem.getException());
else
return true;
return lastItem.isOnCompleted();
}
public T takeNext() throws InterruptedException {
Notification<T> next = buf.take();
if (next.isOnError())
throw Exceptions.propagate(next.getException());
if (next.isOnCompleted())
throw new IllegalStateException("Observable is completed");
return next.getValue();
}
}
}

View File

@@ -1,45 +0,0 @@
/**
* Copyright 2013 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.operators;
import rx.Observable;
import rx.Observer;
import rx.Scheduler;
import rx.Subscription;
import rx.util.functions.Func1;
public class OperationObserveOn {
public static <T> Func1<Observer<T>, Subscription> observeOn(Observable<T> source, Scheduler scheduler) {
return new ObserveOn<>(source, scheduler);
}
private static class ObserveOn<T> implements Func1<Observer<T>, Subscription> {
private final Observable<T> source;
private final Scheduler scheduler;
public ObserveOn(Observable<T> source, Scheduler scheduler) {
this.source = source;
this.scheduler = scheduler;
}
@Override
public Subscription call(final Observer<T> observer) {
return source.subscribe(new ScheduledObserver<>(observer, scheduler));
}
}
}

View File

@@ -1,108 +0,0 @@
/**
* Copyright 2013 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.operators;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicReference;
import rx.Observable;
import rx.Observer;
import rx.Subscription;
import rx.util.AtomicObservableSubscription;
import rx.util.CompositeException;
import rx.util.functions.Func1;
public final class OperationOnErrorResumeNextViaFunction<T> {
public static <T> Func1<Observer<T>, Subscription> onErrorResumeNextViaFunction(Observable<T> originalSequence, Func1<Exception, Observable<T>> resumeFunction) {
return new OnErrorResumeNextViaFunction<>(originalSequence, resumeFunction);
}
private static class OnErrorResumeNextViaFunction<T> implements Func1<Observer<T>, Subscription> {
private final Func1<Exception, Observable<T>> resumeFunction;
private final Observable<T> originalSequence;
public OnErrorResumeNextViaFunction(Observable<T> originalSequence, Func1<Exception, Observable<T>> resumeFunction) {
this.resumeFunction = resumeFunction;
this.originalSequence = originalSequence;
}
@Override
public Subscription call(final Observer<T> observer) {
// AtomicReference since we'll be accessing/modifying this across threads so we can switch it if needed
final AtomicReference<AtomicObservableSubscription> subscriptionRef = new AtomicReference<>(new AtomicObservableSubscription());
// subscribe to the original Observable and remember the subscription
subscriptionRef.get().wrap(new AtomicObservableSubscription(originalSequence.subscribe(new Observer<T>() {
@Override
public void onNext(T value) {
// forward the successful calls
observer.onNext(value);
}
/**
* Instead of passing the onError forward, we intercept and
* "resume" with the resumeSequence.
*/
@Override
public void onError(Exception ex) {
/*
* remember what the current subscription is so we can
* determine if someone unsubscribes concurrently
*/
AtomicObservableSubscription currentSubscription = subscriptionRef.get();
// check that we have not been unsubscribed before we can process the error
if (currentSubscription != null)
try {
Observable<T> resumeSequence = resumeFunction.call(ex);
/*
* error occurred, so switch subscription to the
* 'resumeSequence'
*/
AtomicObservableSubscription innerSubscription = new AtomicObservableSubscription(resumeSequence.subscribe(observer));
/*
* we changed the sequence, so also change the
* subscription to the one of the 'resumeSequence'
* instead
*/
if (!subscriptionRef.compareAndSet(currentSubscription, innerSubscription))
// we failed to set which means 'subscriptionRef' was set to NULL via the unsubscribe below
// so we want to immediately unsubscribe from the resumeSequence we just subscribed to
innerSubscription.unsubscribe();
} catch (Exception e) {
// the resume function failed so we need to call onError
// I am using CompositeException so that both exceptions can be seen
observer.onError(new CompositeException("OnErrorResume function failed", Arrays.asList(ex, e)));
}
}
@Override
public void onCompleted() {
// forward the successful calls
observer.onCompleted();
}
})));
return () -> {
// this will get either the original, or the resumeSequence one and unsubscribe on it
Subscription s = subscriptionRef.getAndSet(null);
if (s != null)
s.unsubscribe();
};
}
}
}

View File

@@ -1,101 +0,0 @@
/**
* Copyright 2013 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.operators;
import java.util.concurrent.atomic.AtomicReference;
import rx.Observable;
import rx.Observer;
import rx.Subscription;
import rx.util.AtomicObservableSubscription;
import rx.util.functions.Func1;
public final class OperationOnErrorResumeNextViaObservable<T> {
public static <T> Func1<Observer<T>, Subscription> onErrorResumeNextViaObservable(Observable<T> originalSequence, Observable<T> resumeSequence) {
return new OnErrorResumeNextViaObservable<>(originalSequence, resumeSequence);
}
private static class OnErrorResumeNextViaObservable<T> implements Func1<Observer<T>, Subscription> {
private final Observable<T> resumeSequence;
private final Observable<T> originalSequence;
public OnErrorResumeNextViaObservable(Observable<T> originalSequence, Observable<T> resumeSequence) {
this.resumeSequence = resumeSequence;
this.originalSequence = originalSequence;
}
public Subscription call(final Observer<T> observer) {
final AtomicObservableSubscription subscription = new AtomicObservableSubscription();
// AtomicReference since we'll be accessing/modifying this across threads so we can switch it if needed
final AtomicReference<AtomicObservableSubscription> subscriptionRef = new AtomicReference<>(subscription);
// subscribe to the original Observable and remember the subscription
subscription.wrap(originalSequence.subscribe(new Observer<T>() {
@Override
public void onNext(T value) {
// forward the successful calls
observer.onNext(value);
}
/**
* Instead of passing the onError forward, we intercept and
* "resume" with the resumeSequence.
*/
@Override
public void onError(Exception ex) {
/*
* remember what the current subscription is so we can
* determine if someone unsubscribes concurrently
*/
AtomicObservableSubscription currentSubscription = subscriptionRef.get();
// check that we have not been unsubscribed before we can process the error
if (currentSubscription != null) {
/*
* error occurred, so switch subscription to the
* 'resumeSequence'
*/
AtomicObservableSubscription innerSubscription = new AtomicObservableSubscription(resumeSequence.subscribe(observer));
/*
* we changed the sequence, so also change the
* subscription to the one of the 'resumeSequence'
* instead
*/
if (!subscriptionRef.compareAndSet(currentSubscription, innerSubscription))
// we failed to set which means 'subscriptionRef' was set to NULL via the unsubscribe below
// so we want to immediately unsubscribe from the resumeSequence we just subscribed to
innerSubscription.unsubscribe();
}
}
@Override
public void onCompleted() {
// forward the successful calls
observer.onCompleted();
}
}));
return () -> {
// this will get either the original, or the resumeSequence one and unsubscribe on it
Subscription s = subscriptionRef.getAndSet(null);
if (s != null)
s.unsubscribe();
};
}
}
}

View File

@@ -1,125 +0,0 @@
/**
* Copyright 2013 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.operators;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicReference;
import rx.Observable;
import rx.Observer;
import rx.Subscription;
import rx.util.AtomicObservableSubscription;
import rx.util.CompositeException;
import rx.util.functions.Func1;
/**
* When an onError occurs the resumeFunction will be executed and it's response
* passed to onNext instead of calling onError.
*/
public final class OperationOnErrorReturn<T> {
public static <T> Func1<Observer<T>, Subscription> onErrorReturn(Observable<T> originalSequence, Func1<Exception, T> resumeFunction) {
return new OnErrorReturn<>(originalSequence, resumeFunction);
}
private static class OnErrorReturn<T> implements Func1<Observer<T>, Subscription> {
private final Func1<Exception, T> resumeFunction;
private final Observable<T> originalSequence;
public OnErrorReturn(Observable<T> originalSequence, Func1<Exception, T> resumeFunction) {
this.resumeFunction = resumeFunction;
this.originalSequence = originalSequence;
}
@Override
public Subscription call(final Observer<T> observer) {
final AtomicObservableSubscription subscription = new AtomicObservableSubscription();
// AtomicReference since we'll be accessing/modifying this across threads so we can switch it if needed
final AtomicReference<AtomicObservableSubscription> subscriptionRef = new AtomicReference<>(subscription);
// subscribe to the original Observable and remember the subscription
subscription.wrap(originalSequence.subscribe(new Observer<T>() {
@Override
public void onNext(T value) {
// forward the successful calls
observer.onNext(value);
}
/**
* Instead of passing the onError forward, we intercept and
* "resume" with the resumeSequence.
*/
@Override
public void onError(Exception ex) {
/*
* remember what the current subscription is so we can
* determine if someone unsubscribes concurrently
*/
AtomicObservableSubscription currentSubscription = subscriptionRef.get();
// check that we have not been unsubscribed before we can process the error
if (currentSubscription != null)
try {
/*
* error occurred, so execute the function, give it
* the exception and call onNext with the response
*/
onNext(resumeFunction.call(ex));
/*
* we are not handling an exception thrown from this
* function ... should we do something?
* error handling within an error handler is a weird
* one to determine what we should do
* right now I'm going to just let it throw whatever
* exceptions occur (such as NPE)
* but I'm considering calling the original
* Observer.onError to act as if this OnErrorReturn
* operator didn't happen
*/
/*
* we are now completed
*/
onCompleted();
/*
* unsubscribe since it blew up
*/
currentSubscription.unsubscribe();
} catch (Exception e) {
// the return function failed so we need to call onError
// I am using CompositeException so that both exceptions can be seen
observer.onError(new CompositeException("OnErrorReturn function failed", Arrays.asList(ex, e)));
}
}
@Override
public void onCompleted() {
// forward the successful calls
observer.onCompleted();
}
}));
return () -> {
// this will get either the original, or the resumeSequence one and unsubscribe on it
Subscription s = subscriptionRef.getAndSet(null);
if (s != null)
s.unsubscribe();
};
}
}
}

View File

@@ -1,136 +0,0 @@
/**
* Copyright 2013 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.operators;
import rx.Observable;
import rx.Observer;
import rx.Subscription;
import rx.util.AtomicObservableSubscription;
import rx.util.functions.Func1;
import rx.util.functions.Func2;
public final class OperationScan {
/**
* Applies an accumulator function over an observable sequence and returns
* each intermediate result with the specified source and accumulator.
*
* @param sequence An observable sequence of elements to project.
* @param initialValue The initial (seed) accumulator value.
* @param accumulator An accumulator function to be invoked on each element
* from the sequence.
*
* @return An observable sequence whose elements are the result of
* accumulating the output from the list of Observables.
*
* @see http://msdn.microsoft.com/en-us/library/hh211665(v=vs.103).aspx
*/
public static <T> Func1<Observer<T>, Subscription> scan(Observable<T> sequence, T initialValue, Func2<T, T, T> accumulator) {
return new Accumulator<>(sequence, initialValue, accumulator);
}
/**
* Applies an accumulator function over an observable sequence and returns
* each intermediate result with the specified source and accumulator.
*
* @param sequence An observable sequence of elements to project.
* @param accumulator An accumulator function to be invoked on each element
* from the sequence.
*
* @return An observable sequence whose elements are the result of
* accumulating the output from the list of Observables.
*
* @see http://msdn.microsoft.com/en-us/library/hh211665(v=vs.103).aspx
*/
public static <T> Func1<Observer<T>, Subscription> scan(Observable<T> sequence, Func2<T, T, T> accumulator) {
return new Accumulator<>(sequence, null, accumulator);
}
private static class Accumulator<T> implements Func1<Observer<T>, Subscription> {
private final Observable<T> sequence;
private final T initialValue;
private final Func2<T, T, T> accumlatorFunction;
private final AtomicObservableSubscription subscription = new AtomicObservableSubscription();
private Accumulator(Observable<T> sequence, T initialValue, Func2<T, T, T> accumulator) {
this.sequence = sequence;
this.initialValue = initialValue;
this.accumlatorFunction = accumulator;
}
@Override
public Subscription call(final Observer<T> observer) {
return subscription.wrap(sequence.subscribe(new Observer<T>() {
private T acc = initialValue;
private boolean hasSentInitialValue = false;
/**
* We must synchronize this because we can't allow multiple
* threads to execute the 'accumulatorFunction' at the same time
* because the accumulator code very often will be doing
* mutation of the 'acc' object such as a non-threadsafe HashMap
*
* Because it's synchronized it's using non-atomic variables
* since everything in this method is single-threaded
*/
@Override
public synchronized void onNext(T value) {
if (acc == null) {
// we assume that acc is not allowed to be returned from accumulatorValue
// so it's okay to check null as being the state we initialize on
acc = value;
// this is all we do for this first value if we didn't have an initialValue
return;
}
if (!hasSentInitialValue) {
hasSentInitialValue = true;
observer.onNext(acc);
}
try {
acc = accumlatorFunction.call(acc, value);
if (acc == null) {
onError(new IllegalArgumentException("Null is an unsupported return value for an accumulator."));
return;
}
observer.onNext(acc);
} catch (Exception ex) {
observer.onError(ex);
// this will work if the sequence is asynchronous, it will have no effect on a synchronous observable
subscription.unsubscribe();
}
}
@Override
public void onError(Exception ex) {
observer.onError(ex);
}
// synchronized because we access 'hasSentInitialValue'
@Override
public synchronized void onCompleted() {
// if only one sequence value existed, we send it without any accumulation
if (!hasSentInitialValue)
observer.onNext(acc);
observer.onCompleted();
}
}));
}
}
}

View File

@@ -1,105 +0,0 @@
/**
* Copyright 2013 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.operators;
import java.util.concurrent.atomic.AtomicInteger;
import rx.Observable;
import rx.Observer;
import rx.Subscription;
import rx.util.functions.Func1;
/**
* Skips a specified number of contiguous values from the start of a Observable
* sequence and then returns the remaining values.
*/
public final class OperationSkip {
/**
* Skips a specified number of contiguous values from the start of a
* Observable sequence and then returns the remaining values.
*
* @param items
* @param num
*
* @return
*
* @see http://msdn.microsoft.com/en-us/library/hh229847(v=vs.103).aspx
*/
public static <T> Func1<Observer<T>, Subscription> skip(final Observable<T> items, final int num) {
// wrap in a Observable so that if a chain is built up, then asynchronously subscribed to twice we will have 2 instances of Take<T> rather than 1 handing both, which is not thread-safe.
return new Skip<>(items, num)::call;
}
/**
* This class is NOT thread-safe if invoked and referenced multiple times.
* In other words, don't subscribe to it multiple times from different
* threads.
* <p>
* It IS thread-safe from within it while receiving onNext events from
* multiple threads.
*
* @param <T>
*/
private static class Skip<T> implements Func1<Observer<T>, Subscription> {
private final int num;
private final Observable<T> items;
Skip(final Observable<T> items, final int num) {
this.num = num;
this.items = items;
}
@Override
public Subscription call(Observer<T> observer) {
return items.subscribe(new ItemObserver(observer));
}
/**
* Used to subscribe to the 'items' Observable sequence and forward to
* the actualObserver up to 'num' count.
*/
private class ItemObserver implements Observer<T> {
private AtomicInteger counter = new AtomicInteger();
private final Observer<T> observer;
public ItemObserver(Observer<T> observer) {
this.observer = observer;
}
@Override
public void onCompleted() {
observer.onCompleted();
}
@Override
public void onError(Exception e) {
observer.onError(e);
}
@Override
public void onNext(T args) {
// skip them until we reach the 'num' value
if (counter.incrementAndGet() > num)
observer.onNext(args);
}
}
}
}

View File

@@ -1,62 +0,0 @@
/**
* Copyright 2013 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.operators;
import rx.Observable;
import rx.Observer;
import rx.Scheduler;
import rx.Subscription;
import rx.util.functions.Func1;
public class OperationSubscribeOn {
public static <T> Func1<Observer<T>, Subscription> subscribeOn(Observable<T> source, Scheduler scheduler) {
return new SubscribeOn<>(source, scheduler);
}
private static class SubscribeOn<T> implements Func1<Observer<T>, Subscription> {
private final Observable<T> source;
private final Scheduler scheduler;
public SubscribeOn(Observable<T> source, Scheduler scheduler) {
this.source = source;
this.scheduler = scheduler;
}
@Override
public Subscription call(final Observer<T> observer) {
return scheduler.schedule(() -> new ScheduledSubscription(source.subscribe(observer), scheduler));
}
}
private static class ScheduledSubscription implements Subscription {
private final Subscription underlying;
private final Scheduler scheduler;
private ScheduledSubscription(Subscription underlying, Scheduler scheduler) {
this.underlying = underlying;
this.scheduler = scheduler;
}
@Override
public void unsubscribe() {
scheduler.schedule(underlying::unsubscribe);
}
}
}

View File

@@ -1,75 +0,0 @@
/**
* Copyright 2013 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.operators;
import rx.Observable;
import rx.Observer;
import rx.Subscription;
import rx.util.AtomicObservableSubscription;
import rx.util.SynchronizedObserver;
import rx.util.functions.Func1;
/**
* An observable that wraps an observable of the same type and then enforces the
* semantics expected of a well-behaved observable.
* <p>
* An observable that ensures onNext, onCompleted, or onError calls on its
* subscribers are not interleaved, onCompleted and onError are only called once
* respectively, and no onNext calls follow onCompleted and onError calls.
* <p>
* NOTE: {@link Observable#create} already wraps Observables so this is
* generally redundant.
*
* @param <T> The type of the observable sequence.
*/
public final class OperationSynchronize<T> {
/**
* Accepts an observable and wraps it in another observable which ensures
* that the resulting observable is well-behaved.
*
* A well-behaved observable ensures onNext, onCompleted, or onError calls
* to its subscribers are not interleaved, onCompleted and onError are only
* called once respectively, and no onNext calls follow onCompleted and
* onError calls.
*
* @param observable
* @param <T>
*
* @return
*/
public static <T> Func1<Observer<T>, Subscription> synchronize(Observable<T> observable) {
return new Synchronize<>(observable);
}
private static class Synchronize<T> implements Func1<Observer<T>, Subscription> {
public Synchronize(Observable<T> innerObservable) {
this.innerObservable = innerObservable;
}
private final Observable<T> innerObservable;
private SynchronizedObserver<T> atomicObserver;
@Override
public Subscription call(Observer<T> observer) {
AtomicObservableSubscription subscription = new AtomicObservableSubscription();
atomicObserver = new SynchronizedObserver<>(observer, subscription);
return subscription.wrap(innerObservable.subscribe(atomicObserver));
}
}
}

View File

@@ -1,135 +0,0 @@
/**
* Copyright 2013 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.operators;
import java.util.concurrent.atomic.AtomicInteger;
import rx.Observable;
import rx.Observer;
import rx.Subscription;
import rx.subscriptions.Subscriptions;
import rx.util.AtomicObservableSubscription;
import rx.util.functions.Func1;
/**
* Returns a specified number of contiguous values from the start of an
* observable sequence.
*/
public final class OperationTake {
/**
* Returns a specified number of contiguous values from the start of an
* observable sequence.
*
* @param items
* @param num
*
* @return
*/
public static <T> Func1<Observer<T>, Subscription> take(final Observable<T> items, final int num) {
// wrap in a Func so that if a chain is built up, then asynchronously subscribed to twice we will have 2 instances of Take<T> rather than 1 handing both, which is not thread-safe.
return new Take<>(items, num)::call;
}
/**
* This class is NOT thread-safe if invoked and referenced multiple times.
* In other words, don't subscribe to it multiple times from different
* threads.
* <p>
* It IS thread-safe from within it while receiving onNext events from
* multiple threads.
* <p>
* This should all be fine as long as it's kept as a private class and a new
* instance created from static factory method above.
* <p>
* Note how the take() factory method above protects us from a single
* instance being exposed with the Observable wrapper handling the subscribe
* flow.
*
* @param <T>
*/
private static class Take<T> implements Func1<Observer<T>, Subscription> {
private final AtomicInteger counter = new AtomicInteger();
private final Observable<T> items;
private final int num;
private final AtomicObservableSubscription subscription = new AtomicObservableSubscription();
private Take(Observable<T> items, int num) {
this.items = items;
this.num = num;
}
@Override
public Subscription call(Observer<T> observer) {
if (num < 1) {
items.subscribe(new Observer<T>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Exception e) {
}
@Override
public void onNext(T args) {
}
}).unsubscribe();
observer.onCompleted();
return Subscriptions.empty();
}
return subscription.wrap(items.subscribe(new ItemObserver(observer)));
}
private class ItemObserver implements Observer<T> {
private final Observer<T> observer;
public ItemObserver(Observer<T> observer) {
this.observer = observer;
}
@Override
public void onCompleted() {
if (counter.getAndSet(num) < num)
observer.onCompleted();
}
@Override
public void onError(Exception e) {
if (counter.getAndSet(num) < num)
observer.onError(e);
}
@Override
public void onNext(T args) {
final int count = counter.incrementAndGet();
if (count <= num) {
observer.onNext(args);
if (count == num)
observer.onCompleted();
}
if (count >= num)
// this will work if the sequence is asynchronous, it will have no effect on a synchronous observable
subscription.unsubscribe();
}
}
}
}

View File

@@ -1,84 +0,0 @@
/**
* Copyright 2013 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.operators;
import java.util.Iterator;
import java.util.concurrent.LinkedBlockingDeque;
import rx.Observable;
import rx.Observer;
import rx.Subscription;
import rx.util.AtomicObservableSubscription;
import rx.util.functions.Func1;
/**
* Returns a specified number of contiguous elements from the end of an
* observable sequence.
*/
public final class OperationTakeLast {
public static <T> Func1<Observer<T>, Subscription> takeLast(final Observable<T> items, final int count) {
return new TakeLast<>(items, count)::call;
}
private static class TakeLast<T> implements Func1<Observer<T>, Subscription> {
private final int count;
private final Observable<T> items;
private final AtomicObservableSubscription subscription = new AtomicObservableSubscription();
TakeLast(final Observable<T> items, final int count) {
this.count = count;
this.items = items;
}
@Override
public Subscription call(Observer<T> observer) {
return subscription.wrap(items.subscribe(new ItemObserver(observer)));
}
private class ItemObserver implements Observer<T> {
private LinkedBlockingDeque<T> deque = new LinkedBlockingDeque<>(count);
private final Observer<T> observer;
public ItemObserver(Observer<T> observer) {
this.observer = observer;
}
@Override
public void onCompleted() {
Iterator<T> reverse = deque.descendingIterator();
while (reverse.hasNext())
observer.onNext(reverse.next());
observer.onCompleted();
}
@Override
public void onError(Exception e) {
observer.onError(e);
}
@Override
public void onNext(T args) {
while (!deque.offerFirst(args))
deque.removeLast();
}
}
}
}

View File

@@ -1,144 +0,0 @@
/**
* Copyright 2013 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.operators;
import java.util.concurrent.atomic.AtomicInteger;
import rx.Observable;
import rx.Observer;
import rx.Subscription;
import rx.util.AtomicObservableSubscription;
import rx.util.AtomicObserver;
import rx.util.functions.Func1;
import rx.util.functions.Func2;
/**
* Returns values from an observable sequence as long as a specified condition
* is true, and then skips the remaining values.
*/
public final class OperationTakeWhile {
/**
* Returns a specified number of contiguous values from the start of an
* observable sequence.
*
* @param items
* @param predicate a function to test each source element for a condition
*
* @return
*/
public static <T> Func1<Observer<T>, Subscription> takeWhile(final Observable<T> items, final Func1<T, Boolean> predicate) {
return takeWhileWithIndex(items, OperationTakeWhile.<T>skipIndex(predicate));
}
/**
* Returns values from an observable sequence as long as a specified
* condition is true, and then skips the remaining values.
*
* @param items
* @param predicate a function to test each element for a condition; the
* second parameter of the function represents the index of the source
* element; otherwise, false.
*
* @return
*/
public static <T> Func1<Observer<T>, Subscription> takeWhileWithIndex(final Observable<T> items, final Func2<T, Integer, Boolean> predicate) {
// wrap in a Func so that if a chain is built up, then asynchronously subscribed to twice we will have 2 instances of Take<T> rather than 1 handing both, which is not thread-safe.
return new TakeWhile<T>(items, predicate)::call;
}
private static <T> Func2<T, Integer, Boolean> skipIndex(final Func1<T, Boolean> underlying) {
return (T input, Integer index) -> underlying.call(input);
}
/**
* This class is NOT thread-safe if invoked and referenced multiple times.
* In other words, don't subscribe to it multiple times from different
* threads.
* <p>
* It IS thread-safe from within it while receiving onNext events from
* multiple threads.
* <p>
* This should all be fine as long as it's kept as a private class and a new
* instance created from static factory method above.
* <p>
* Note how the takeWhileWithIndex() factory method above protects us from a
* single instance being exposed with the Observable wrapper handling the
* subscribe flow.
*
* @param <T>
*/
private static class TakeWhile<T> implements Func1<Observer<T>, Subscription> {
private final AtomicInteger counter = new AtomicInteger();
private final Observable<T> items;
private final Func2<T, Integer, Boolean> predicate;
private final AtomicObservableSubscription subscription = new AtomicObservableSubscription();
private TakeWhile(Observable<T> items, Func2<T, Integer, Boolean> predicate) {
this.items = items;
this.predicate = predicate;
}
@Override
public Subscription call(Observer<T> observer) {
return subscription.wrap(items.subscribe(new ItemObserver(observer)));
}
private class ItemObserver implements Observer<T> {
private final Observer<T> observer;
public ItemObserver(Observer<T> observer) {
// Using AtomicObserver because the unsubscribe, onCompleted, onError and error handling behavior
// needs "isFinished" logic to not send duplicated events
// The 'testTakeWhile1' and 'testTakeWhile2' tests fail without this.
this.observer = new AtomicObserver<>(subscription, observer);
}
@Override
public void onCompleted() {
observer.onCompleted();
}
@Override
public void onError(Exception e) {
observer.onError(e);
}
@Override
public void onNext(T args) {
Boolean isSelected;
try {
isSelected = predicate.call(args, counter.getAndIncrement());
} catch (Exception e) {
observer.onError(e);
return;
}
if (isSelected)
observer.onNext(args);
else {
observer.onCompleted();
// this will work if the sequence is asynchronous, it will have no effect on a synchronous observable
subscription.unsubscribe();
}
}
}
}
}

View File

@@ -1,71 +0,0 @@
/**
* Copyright 2013 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.operators;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import rx.Observer;
import rx.Subscription;
import rx.subscriptions.Subscriptions;
import rx.util.functions.Func1;
public class OperationToObservableFuture {
private static class ToObservableFuture<T> implements Func1<Observer<T>, Subscription> {
private final Future<T> that;
private final Long time;
private final TimeUnit unit;
public ToObservableFuture(Future<T> that) {
this.that = that;
this.time = null;
this.unit = null;
}
public ToObservableFuture(Future<T> that, long time, TimeUnit unit) {
this.that = that;
this.time = time;
this.unit = unit;
}
@Override
public Subscription call(Observer<T> observer) {
try {
T value = (time == null) ? that.get() : that.get(time, unit);
if (!that.isCancelled())
observer.onNext(value);
observer.onCompleted();
} catch (Exception e) {
observer.onError(e);
}
// the get() has already completed so there is no point in
// giving the user a way to cancel.
return Subscriptions.empty();
}
}
public static <T> Func1<Observer<T>, Subscription> toObservableFuture(final Future<T> that) {
return new ToObservableFuture<>(that);
}
public static <T> Func1<Observer<T>, Subscription> toObservableFuture(final Future<T> that, long time, TimeUnit unit) {
return new ToObservableFuture<>(that, time, unit);
}
}

View File

@@ -1,39 +0,0 @@
/**
* Copyright 2013 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.operators;
import rx.Observer;
import rx.Subscription;
import rx.subscriptions.Subscriptions;
import rx.util.functions.Func1;
/**
* Accepts an Iterable object and exposes it as an Observable.
*
* @param <T> The type of the Iterable sequence.
*/
public final class OperationToObservableIterable<T> {
public static <T> Func1<Observer<T>, Subscription> toObservableIterable(Iterable<T> iterable) {
return (Observer<T> observer) -> {
for (T item : iterable)
observer.onNext(item);
observer.onCompleted();
return Subscriptions.empty();
};
}
}

View File

@@ -1,79 +0,0 @@
/**
* Copyright 2013 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.operators;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;
import rx.Observable;
import rx.Observer;
import rx.Subscription;
import rx.util.functions.Func1;
public final class OperationToObservableList<T> {
public static <T> Func1<Observer<List<T>>, Subscription> toObservableList(Observable<T> that) {
return new ToObservableList<>(that);
}
private static class ToObservableList<T> implements Func1<Observer<List<T>>, Subscription> {
private final Observable<T> that;
public ToObservableList(Observable<T> that) {
this.that = that;
}
@Override
public Subscription call(final Observer<List<T>> observer) {
return that.subscribe(new Observer<T>() {
final ConcurrentLinkedQueue<T> list = new ConcurrentLinkedQueue<>();
@Override
public void onNext(T value) {
// onNext can be concurrently executed so list must be thread-safe
list.add(value);
}
@Override
public void onError(Exception ex) {
observer.onError(ex);
}
@Override
public void onCompleted() {
try {
// copy from LinkedQueue to List since ConcurrentLinkedQueue does not implement the List interface
ArrayList<T> l = new ArrayList<>(list.size());
for (T t : list)
l.add(t);
// benjchristensen => I want to make this list immutable but some clients are sorting this
// instead of using toSortedList() and this change breaks them until we migrate their code.
// observer.onNext(Collections.unmodifiableList(l));
observer.onNext(l);
observer.onCompleted();
} catch (Exception e) {
onError(e);
}
}
});
}
}
}

View File

@@ -1,131 +0,0 @@
/**
* Copyright 2013 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.operators;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;
import rx.Observable;
import rx.Observer;
import rx.Subscription;
import rx.util.functions.Func1;
import rx.util.functions.Func2;
/**
* Similar to toList in that it converts a sequence<T> into a List<T> except
* that it accepts a Function that will provide an implementation of Comparator.
*
* @param <T>
*/
public final class OperationToObservableSortedList<T> {
/**
* Sort T objects by their natural order (object must implement Comparable).
*
* @param sequence
*
* @throws ClassCastException if T objects do not implement Comparable
* @return
*/
public static <T> Func1<Observer<List<T>>, Subscription> toSortedList(Observable<T> sequence) {
return new ToObservableSortedList<>(sequence);
}
/**
* Sort T objects using the defined sort function.
*
* @param sequence
* @param sortFunction
*
* @return
*/
public static <T> Func1<Observer<List<T>>, Subscription> toSortedList(Observable<T> sequence, Func2<T, T, Integer> sortFunction) {
return new ToObservableSortedList<>(sequence, sortFunction);
}
private static class ToObservableSortedList<T> implements Func1<Observer<List<T>>, Subscription> {
private final Observable<T> that;
private final ConcurrentLinkedQueue<T> list = new ConcurrentLinkedQueue<>();
private final Func2<T, T, Integer> sortFunction;
// unchecked as we're support Object for the default
@SuppressWarnings("unchecked")
private ToObservableSortedList(Observable<T> that) {
this(that, defaultSortFunction);
}
private ToObservableSortedList(Observable<T> that, Func2<T, T, Integer> sortFunction) {
this.that = that;
this.sortFunction = sortFunction;
}
@Override
public Subscription call(final Observer<List<T>> observer) {
return that.subscribe(new Observer<T>() {
@Override
public void onNext(T value) {
// onNext can be concurrently executed so list must be thread-safe
list.add(value);
}
@Override
public void onError(Exception ex) {
observer.onError(ex);
}
@Override
public void onCompleted() {
try {
// copy from LinkedQueue to List since ConcurrentLinkedQueue does not implement the List interface
ArrayList<T> l = new ArrayList<>(list.size());
for (T t : list)
l.add(t);
// sort the list before delivery
Collections.sort(l, (T o1, T o2) -> sortFunction.call(o1, o2));
observer.onNext(Collections.unmodifiableList(l));
observer.onCompleted();
} catch (Exception e) {
onError(e);
}
}
});
}
// raw because we want to support Object for this default
@SuppressWarnings("rawtypes")
private static Func2 defaultSortFunction = new DefaultComparableFunction();
private static class DefaultComparableFunction implements Func2<Object, Object, Integer> {
// unchecked because we want to support Object for this default
@SuppressWarnings("unchecked")
@Override
public Integer call(Object t1, Object t2) {
Comparable<Object> c1 = (Comparable<Object>) t1;
Comparable<Object> c2 = (Comparable<Object>) t2;
return c1.compareTo(c2);
}
}
}
}

View File

@@ -1,28 +0,0 @@
/**
* Copyright 2013 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.operators;
import rx.Observable;
import rx.Observer;
import rx.Subscription;
import rx.util.functions.Func1;
public final class OperationWhere {
public static <T> Func1<Observer<T>, Subscription> where(Observable<T> that, Func1<T, Boolean> predicate) {
return OperationFilter.filter(that, predicate);
}
}

View File

@@ -1,284 +0,0 @@
/**
* Copyright 2013 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.operators;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import rx.Observable;
import rx.Observer;
import rx.Subscription;
import rx.util.AtomicObservableSubscription;
import rx.util.SynchronizedObserver;
import rx.util.functions.Func1;
import rx.util.functions.Func2;
import rx.util.functions.Func3;
import rx.util.functions.Func4;
import rx.util.functions.FuncN;
import rx.util.functions.Functions;
public final class OperationZip {
public static <T0, T1, R> Func1<Observer<R>, Subscription> zip(Observable<T0> w0, Observable<T1> w1, Func2<T0, T1, R> zipFunction) {
Aggregator<R> a = new Aggregator<>(Functions.fromFunc(zipFunction));
a.addObserver(new ZipObserver<>(a, w0));
a.addObserver(new ZipObserver<>(a, w1));
return a;
}
public static <T0, T1, T2, R> Func1<Observer<R>, Subscription> zip(Observable<T0> w0, Observable<T1> w1, Observable<T2> w2, Func3<T0, T1, T2, R> zipFunction) {
Aggregator<R> a = new Aggregator<>(Functions.fromFunc(zipFunction));
a.addObserver(new ZipObserver<>(a, w0));
a.addObserver(new ZipObserver<>(a, w1));
a.addObserver(new ZipObserver<>(a, w2));
return a;
}
public static <T0, T1, T2, T3, R> Func1<Observer<R>, Subscription> zip(Observable<T0> w0, Observable<T1> w1, Observable<T2> w2, Observable<T3> w3, Func4<T0, T1, T2, T3, R> zipFunction) {
Aggregator<R> a = new Aggregator<>(Functions.fromFunc(zipFunction));
a.addObserver(new ZipObserver<>(a, w0));
a.addObserver(new ZipObserver<>(a, w1));
a.addObserver(new ZipObserver<>(a, w2));
a.addObserver(new ZipObserver<>(a, w3));
return a;
}
/*
* ThreadSafe
*/
private static class ZipObserver<R, T> implements Observer<T> {
final Observable<T> w;
final Aggregator<R> a;
private final AtomicObservableSubscription subscription = new AtomicObservableSubscription();
private final AtomicBoolean subscribed = new AtomicBoolean(false);
public ZipObserver(Aggregator<R> a, Observable<T> w) {
this.a = a;
this.w = w;
}
public void startWatching() {
if (subscribed.compareAndSet(false, true))
// only subscribe once even if called more than once
subscription.wrap(w.subscribe(this));
}
@Override
public void onCompleted() {
a.complete(this);
}
@Override
public void onError(Exception e) {
a.error(this, e);
}
@Override
public void onNext(T args) {
try {
a.next(this, args);
} catch (Exception e) {
onError(e);
}
}
}
/**
* Receive notifications from each of the Observables we are reducing and
* execute the zipFunction whenever we have received events from all
* Observables.
*
* This class is thread-safe.
*
* @param <T>
*/
private static class Aggregator<T> implements Func1<Observer<T>, Subscription> {
private volatile SynchronizedObserver<T> observer;
private final FuncN<T> zipFunction;
private final AtomicBoolean started = new AtomicBoolean(false);
private final AtomicBoolean running = new AtomicBoolean(true);
private final ConcurrentHashMap<ZipObserver<T, ?>, Boolean> completed = new ConcurrentHashMap<>();
/*
* we use ConcurrentHashMap despite synchronization of methods because
* stop() does NOT use synchronization and this map is used by it and
* can be called by other threads
*/
private final ConcurrentHashMap<ZipObserver<T, ?>, ConcurrentLinkedQueue<Object>> receivedValuesPerObserver = new ConcurrentHashMap<>();
/*
* we use a ConcurrentLinkedQueue to retain ordering (I'd like to just
* use a ConcurrentLinkedHashMap for 'receivedValuesPerObserver' but
* that doesn't exist in standard java
*/
private final ConcurrentLinkedQueue<ZipObserver<T, ?>> observers = new ConcurrentLinkedQueue<>();
public Aggregator(FuncN<T> zipFunction) {
this.zipFunction = zipFunction;
}
/**
* Receive notification of a Observer starting (meaning we should
* require it for aggregation)
*
* Thread Safety => Invoke ONLY from the static factory methods at top
* of this class which are always an atomic execution by a single
* thread.
*
* @param w
*/
private void addObserver(ZipObserver<T, ?> w) {
// initialize this ZipObserver
observers.add(w);
receivedValuesPerObserver.put(w, new ConcurrentLinkedQueue<>());
}
/**
* 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();
}
/**
* 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();
}
}
/**
* 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));
}
@Override
public Subscription call(Observer<T> observer) {
if (started.compareAndSet(false, true)) {
AtomicObservableSubscription subscription = new AtomicObservableSubscription();
this.observer = new SynchronizedObserver<>(observer, subscription);
/*
* start the Observers
*/
for (ZipObserver<T, ?> rw : observers)
rw.startWatching();
return subscription.wrap(this::stop);
} else
/*
* a Observer already has subscribed so blow up
*/
throw new IllegalStateException("Only one Observer can subscribe to this Observable.");
}
/*
* Do NOT synchronize this because it gets called via unsubscribe which
* can occur on other threads
* and result in deadlocks. (http://jira/browse/API-4060)
*
* AtomicObservableSubscription uses compareAndSet instead of locking to
* avoid deadlocks but ensure single-execution.
*
* We do the same in the implementation of this method.
*
* ThreadSafety of this method is provided by:
* - AtomicBoolean[running].compareAndSet
* - ConcurrentLinkedQueue[Observers]
* - ZipObserver.subscription being an AtomicObservableSubscription
*/
private void stop() {
/*
* tell ourselves to stop processing onNext events by setting
* running=false
*/
if (running.compareAndSet(true, false))
/*
* propogate to all Observers to unsubscribe if this thread
* succeeded in setting running=false
*/
for (ZipObserver<T, ?> o : observers)
if (o.subscription != null)
o.subscription.unsubscribe();
}
}
}

View File

@@ -1,117 +0,0 @@
/**
* Copyright 2013 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.operators;
import java.util.concurrent.ConcurrentHashMap;
import rx.Observable;
import rx.Observer;
import rx.Subscription;
import rx.observables.GroupedObservable;
import rx.util.functions.Func1;
import rx.util.functions.Functions;
public final class OperatorGroupBy {
public static <K, T, R> Func1<Observer<GroupedObservable<K, R>>, Subscription> groupBy(Observable<T> source, final Func1<T, K> keySelector, final Func1<T, R> elementSelector) {
final Observable<KeyValue<K, R>> keyval = source.map(new Func1<T, KeyValue<K, R>>() {
@Override
public KeyValue<K, R> call(T t) {
K key = keySelector.call(t);
R value = elementSelector.call(t);
return new KeyValue<K, R>(key, value);
}
});
return new GroupBy<K, R>(keyval);
}
public static <K, T> Func1<Observer<GroupedObservable<K, T>>, Subscription> groupBy(Observable<T> source, final Func1<T, K> keySelector) {
return groupBy(source, keySelector, Functions.<T>identity());
}
private static class GroupBy<K, V> implements Func1<Observer<GroupedObservable<K, V>>, Subscription> {
private final Observable<KeyValue<K, V>> source;
private final ConcurrentHashMap<K, Boolean> keys = new ConcurrentHashMap<K, Boolean>();
private GroupBy(Observable<KeyValue<K, V>> source) {
this.source = source;
}
@Override
public Subscription call(final Observer<GroupedObservable<K, V>> observer) {
return source.subscribe(new Observer<KeyValue<K, V>>() {
@Override
public void onCompleted() {
observer.onCompleted();
}
@Override
public void onError(Exception e) {
observer.onError(e);
}
@Override
public void onNext(final KeyValue<K, V> args) {
K key = args.key;
boolean newGroup = keys.putIfAbsent(key, true) == null;
if (newGroup)
observer.onNext(buildObservableFor(source, key));
}
});
}
}
private static <K, R> GroupedObservable<K, R> buildObservableFor(Observable<KeyValue<K, R>> source, final K key) {
final Observable<R> observable = source.filter(new Func1<KeyValue<K, R>, Boolean>() {
@Override
public Boolean call(KeyValue<K, R> pair) {
return key.equals(pair.key);
}
}).map(new Func1<KeyValue<K, R>, R>() {
@Override
public R call(KeyValue<K, R> pair) {
return pair.value;
}
});
return new GroupedObservable<K, R>(key, new Func1<Observer<R>, Subscription>() {
@Override
public Subscription call(Observer<R> observer) {
return observable.subscribe(observer);
}
});
}
private static class KeyValue<K, V> {
private final K key;
private final V value;
private KeyValue(K key, V value) {
this.key = key;
this.value = value;
}
}
}

View File

@@ -1,141 +0,0 @@
/**
* Copyright 2013 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.operators;
import rx.Observable;
import rx.Observer;
import rx.Subscription;
import rx.util.functions.Func1;
public class OperatorTakeUntil {
/**
* Returns the values from the source observable sequence until the other
* observable sequence produces a value.
*
* @param source the source sequence to propagate elements for.
* @param other the observable sequence that terminates propagation of
* elements of the source sequence.
* @param <T> the type of source.
* @param <E> the other type.
*
* @return An observable sequence containing the elements of the source
* sequence up to the point the other sequence interrupted further
* propagation.
*/
public static <T, E> Observable<T> takeUntil(final Observable<T> source, final Observable<E> other) {
Observable<Notification<T>> s = Observable.create(new SourceObservable<T>(source));
Observable<Notification<T>> o = Observable.create(new OtherObservable<T, E>(other));
@SuppressWarnings("unchecked")
/**
* In JDK 7 we could use 'varargs' instead of 'unchecked'. See
* http://stackoverflow.com/questions/1445233/is-it-possible-to-solve-the-a-generic-array-of-t-is-created-for-a-varargs-param
* and http://hg.openjdk.java.net/jdk7/tl/langtools/rev/46cf751559ae
*/
Observable<Notification<T>> result = Observable.merge(s, o);
return result.takeWhile(new Func1<Notification<T>, Boolean>() {
@Override
public Boolean call(Notification<T> notification) {
return !notification.halt;
}
}).map(new Func1<Notification<T>, T>() {
@Override
public T call(Notification<T> notification) {
return notification.value;
}
});
}
private static class Notification<T> {
private final boolean halt;
private final T value;
public static <T> Notification<T> value(T value) {
return new Notification<T>(false, value);
}
public static <T> Notification<T> halt() {
return new Notification<T>(true, null);
}
private Notification(boolean halt, T value) {
this.halt = halt;
this.value = value;
}
}
private static class SourceObservable<T> implements Func1<Observer<Notification<T>>, Subscription> {
private final Observable<T> sequence;
private SourceObservable(Observable<T> sequence) {
this.sequence = sequence;
}
@Override
public Subscription call(final Observer<Notification<T>> notificationObserver) {
return sequence.subscribe(new Observer<T>() {
@Override
public void onCompleted() {
notificationObserver.onNext(Notification.<T>halt());
}
@Override
public void onError(Exception e) {
notificationObserver.onError(e);
}
@Override
public void onNext(T args) {
notificationObserver.onNext(Notification.value(args));
}
});
}
}
private static class OtherObservable<T, E> implements Func1<Observer<Notification<T>>, Subscription> {
private final Observable<E> sequence;
private OtherObservable(Observable<E> sequence) {
this.sequence = sequence;
}
@Override
public Subscription call(final Observer<Notification<T>> notificationObserver) {
return sequence.subscribe(new Observer<E>() {
@Override
public void onCompleted() {
// Ignore
}
@Override
public void onError(Exception e) {
notificationObserver.onError(e);
}
@Override
public void onNext(E args) {
notificationObserver.onNext(Notification.<T>halt());
}
});
}
}
}

View File

@@ -1,82 +0,0 @@
package rx.operators;
import java.util.Iterator;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import rx.Notification;
import rx.Observable;
import rx.Observer;
import rx.util.Exceptions;
/**
* @see https://github.com/Netflix/RxJava/issues/50
*/
public class OperatorToIterator {
/**
* Returns an iterator that iterates all values of the observable.
*
* @param that an observable sequence to get an iterator for.
* @param <T> the type of source.
*
* @return the iterator that could be used to iterate over the elements of
* the observable.
*/
public static <T> Iterator<T> toIterator(Observable<T> that) {
final BlockingQueue<Notification<T>> notifications = new LinkedBlockingQueue<Notification<T>>();
Observable.materialize(that).subscribe(new Observer<Notification<T>>() {
@Override
public void onCompleted() {
// ignore
}
@Override
public void onError(Exception e) {
// ignore
}
@Override
public void onNext(Notification<T> args) {
notifications.offer(args);
}
});
return new Iterator<T>() {
private Notification<T> buf;
@Override
public boolean hasNext() {
if (buf == null)
buf = take();
return !buf.isOnCompleted();
}
@Override
public T next() {
if (buf == null)
buf = take();
if (buf.isOnError())
throw Exceptions.propagate(buf.getException());
T result = buf.getValue();
buf = null;
return result;
}
private Notification<T> take() {
try {
return notifications.take();
} catch (InterruptedException e) {
throw Exceptions.propagate(e);
}
}
@Override
public void remove() {
throw new UnsupportedOperationException("Read-only iterator");
}
};
}
}

View File

@@ -1,53 +0,0 @@
/**
* Copyright 2013 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.operators;
import rx.Observer;
import rx.Scheduler;
import rx.util.functions.Action0;
/*
* package
*/
class ScheduledObserver<T> implements Observer<T> {
private final Observer<T> underlying;
private final Scheduler scheduler;
public ScheduledObserver(Observer<T> underlying, Scheduler scheduler) {
this.underlying = underlying;
this.scheduler = scheduler;
}
@Override
public void onCompleted() {
scheduler.schedule(() -> {
underlying.onCompleted();
});
}
@Override
public void onError(final Exception e) {
scheduler.schedule(() -> underlying.onError(e));
}
@Override
public void onNext(final T args) {
scheduler.schedule(() -> {
underlying.onNext(args);
});
}
}

View File

@@ -1,45 +0,0 @@
/**
* Copyright 2013 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.plugins;
import rx.Observable;
import rx.Observer;
/**
* Abstract class for defining error handling logic in addition to the normal
* {@link Observer#onError(Exception)} behavior.
* <p>
* For example, all Exceptions can be logged using this handler even if
* {@link Observer#onError(Exception)} is ignored or not provided when an
* {@link Observable} is subscribed to.
* <p>
* See {@link RxJavaPlugins} or the RxJava GitHub Wiki for information on
* configuring plugins: <a
* href="https://github.com/Netflix/RxJava/wiki/Plugins">https://github.com/Netflix/RxJava/wiki/Plugins</a>.
*/
public abstract class RxJavaErrorHandler {
/**
* Receives all Exceptions from an {@link Observable} passed to
* {@link Observer#onError(Exception)}.
*
* @param e Exception
*/
public void handleError(Exception e) {
// do nothing by default
}
}

View File

@@ -1,31 +0,0 @@
/**
* Copyright 2013 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.plugins;
/**
* Default implementation of {@link RxJavaErrorHandler} that does nothing.
*
* @ExcludeFromJavadoc
*/
public class RxJavaErrorHandlerDefault extends RxJavaErrorHandler {
private static RxJavaErrorHandlerDefault INSTANCE = new RxJavaErrorHandlerDefault();
public static RxJavaErrorHandler getInstance() {
return INSTANCE;
}
}

View File

@@ -1,107 +0,0 @@
/**
* Copyright 2013 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.plugins;
import rx.Observable;
import rx.Observer;
import rx.Subscription;
import rx.util.functions.Func1;
/**
* Abstract ExecutionHook with invocations at different lifecycle points of
* {@link Observable} execution with a default no-op implementation.
* <p>
* See {@link RxJavaPlugins} or the RxJava GitHub Wiki for information on
* configuring plugins: <a
* href="https://github.com/Netflix/RxJava/wiki/Plugins">https://github.com/Netflix/RxJava/wiki/Plugins</a>.
* <p>
* <b>Note on thread-safety and performance</b>
* <p>
* A single implementation of this class will be used globally so methods on
* this class will be invoked concurrently from multiple threads so all
* functionality must be thread-safe.
* <p>
* Methods are also invoked synchronously and will add to execution time of the
* observable so all behavior should be fast. If anything time-consuming is to
* be done it should be spawned asynchronously onto separate worker threads.
*
*
*/
public abstract class RxJavaObservableExecutionHook {
/**
* Invoked before {@link Observable#subscribe(rx.Observer)} is about to be
* executed.
* <p>
* This can be used to decorate or replace the <code>onSubscribe</code>
* function or just perform extra logging, metrics and other such things and
* pass-thru the function.
*
* @param observableInstance The executing {@link Observable} instance.
* @param onSubscribe original {@link Func1}<{@link
* Observer}{@code<T>},
* {@link Subscription}> to be executed
*
* @return {@link Func1}<{@link Observer}{@code<T>}, {@link Subscription}>
* function that can be modified, decorated, replaced or just returned as a
* pass-thru.
*/
public <T> Func1<Observer<T>, Subscription> onSubscribeStart(Observable<T> observableInstance, Func1<Observer<T>, Subscription> onSubscribe) {
// pass-thru by default
return onSubscribe;
}
/**
* Invoked after successful execution of
* {@link Observable#subscribe(rx.Observer)} with returned
* {@link Subscription}.
* <p>
* This can be used to decorate or replace the {@link Subscription} instance
* or just perform extra logging, metrics and other such things and
* pass-thru the subscription.
*
* @param observableInstance The executing {@link Observable} instance.
* @param subscription original {@link Subscription}
*
* @return {@link Subscription} subscription that can be modified,
* decorated, replaced or just returned as a pass-thru.
*/
public <T> Subscription onSubscribeReturn(Observable<T> observableInstance, Subscription subscription) {
// pass-thru by default
return subscription;
}
/**
* Invoked after failed execution of {@link Observable#subscribe(Observer)}
* with thrown Exception.
* <p>
* This is NOT errors emitted via {@link Observer#onError(Exception)} but
* exceptions thrown when attempting to subscribe to a {@link Func1}<{@link
* Observer}{@code<T>}, {@link Subscription}>.
*
* @param observableInstance The executing {@link Observable} instance.
* @param e Exception thrown by
* {@link Observable#subscribe(Observer)}
*
* @return Exception that can be decorated, replaced or just returned as a
* pass-thru.
*/
public <T> Exception onSubscribeError(Observable<T> observableInstance, Exception e) {
// pass-thru by default
return e;
}
}

View File

@@ -1,32 +0,0 @@
/**
* Copyright 2013 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.plugins;
/**
* Default no-op implementation of {@link RxJavaObservableExecutionHook}
*/
/*
* package
*/
class RxJavaObservableExecutionHookDefault extends RxJavaObservableExecutionHook {
private static RxJavaObservableExecutionHookDefault INSTANCE = new RxJavaObservableExecutionHookDefault();
public static RxJavaObservableExecutionHook getInstance() {
return INSTANCE;
}
}

View File

@@ -1,156 +0,0 @@
/**
* Copyright 2013 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.plugins;
import java.util.concurrent.atomic.AtomicReference;
/**
* Registry for plugin implementations that allows global override and handles
* the retrieval of correct implementation based on order of precedence:
* <ol>
* <li>plugin registered globally via <code>register</code> methods in this
* class</li>
* <li>plugin registered and retrieved using
* {@link java.lang.System#getProperty(String)} (see get methods for property
* names)</li>
* <li>default implementation</li>
* </ol>
* See the RxJava GitHub Wiki for more information:
* <a href="https://github.com/Netflix/RxJava/wiki/Plugins">https://github.com/Netflix/RxJava/wiki/Plugins</a>.
*/
public class RxJavaPlugins {
private final static RxJavaPlugins INSTANCE = new RxJavaPlugins();
private final AtomicReference<RxJavaErrorHandler> errorHandler = new AtomicReference<RxJavaErrorHandler>();
private final AtomicReference<RxJavaObservableExecutionHook> observableExecutionHook = new AtomicReference<RxJavaObservableExecutionHook>();
private RxJavaPlugins() {
}
public static RxJavaPlugins getInstance() {
return INSTANCE;
}
/**
* Retrieve instance of {@link RxJavaErrorHandler} to use based on order of
* precedence as defined in {@link RxJavaPlugins} class header.
* <p>
* Override default by using
* {@link #registerErrorHandler(RxJavaErrorHandler)} or setting property:
* <code>rxjava.plugin.RxJavaErrorHandler.implementation</code> with the
* full classname to load.
*
* @return {@link RxJavaErrorHandler} implementation to use
*/
public RxJavaErrorHandler getErrorHandler() {
if (errorHandler.get() == null) {
// check for an implementation from System.getProperty first
Object impl = getPluginImplementationViaProperty(RxJavaErrorHandler.class);
if (impl == null)
// nothing set via properties so initialize with default
errorHandler.compareAndSet(null, RxJavaErrorHandlerDefault.getInstance()); // we don't return from here but call get() again in case of thread-race so the winner will always get returned
else
// we received an implementation from the system property so use it
errorHandler.compareAndSet(null, (RxJavaErrorHandler) impl);
}
return errorHandler.get();
}
/**
* Register a {@link RxJavaErrorHandler} implementation as a global override
* of any injected or default implementations.
*
* @param impl {@link RxJavaErrorHandler} implementation
*
* @throws IllegalStateException if called more than once or after the
* default was initialized (if usage occurs before trying to register)
*/
public void registerErrorHandler(RxJavaErrorHandler impl) {
if (!errorHandler.compareAndSet(null, impl))
throw new IllegalStateException("Another strategy was already registered.");
}
/**
* Retrieve instance of {@link RxJavaObservableExecutionHook} to use based
* on order of precedence as defined in {@link RxJavaPlugins} class header.
* <p>
* Override default by using
* {@link #registerObservableExecutionHook(RxJavaObservableExecutionHook)}
* or setting property:
* <code>rxjava.plugin.RxJavaObservableExecutionHook.implementation</code>
* with the full classname to load.
*
* @return {@link RxJavaObservableExecutionHook} implementation to use
*/
public RxJavaObservableExecutionHook getObservableExecutionHook() {
if (observableExecutionHook.get() == null) {
// check for an implementation from System.getProperty first
Object impl = getPluginImplementationViaProperty(RxJavaObservableExecutionHook.class);
if (impl == null)
// nothing set via properties so initialize with default
observableExecutionHook.compareAndSet(null, RxJavaObservableExecutionHookDefault.getInstance()); // we don't return from here but call get() again in case of thread-race so the winner will always get returned
else
// we received an implementation from the system property so use it
observableExecutionHook.compareAndSet(null, (RxJavaObservableExecutionHook) impl);
}
return observableExecutionHook.get();
}
/**
* Register a {@link RxJavaObservableExecutionHook} implementation as a
* global override of any injected or default implementations.
*
* @param impl {@link RxJavaObservableExecutionHook} implementation
*
* @throws IllegalStateException if called more than once or after the
* default was initialized (if usage occurs before trying to register)
*/
public void registerObservableExecutionHook(RxJavaObservableExecutionHook impl) {
if (!observableExecutionHook.compareAndSet(null, impl))
throw new IllegalStateException("Another strategy was already registered.");
}
private static Object getPluginImplementationViaProperty(Class<?> pluginClass) {
String classSimpleName = pluginClass.getSimpleName();
/*
* Check system properties for plugin class.
* <p>
* This will only happen during system startup thus it's okay to use the
* synchronized System.getProperties
* as it will never get called in normal operations.
*/
String implementingClass = System.getProperty("rxjava.plugin." + classSimpleName + ".implementation");
if (implementingClass != null)
try {
Class<?> cls = Class.forName(implementingClass);
// narrow the scope (cast) to the type we're expecting
cls = cls.asSubclass(pluginClass);
return cls.newInstance();
} catch (ClassCastException e) {
throw new RuntimeException(classSimpleName + " implementation is not an instance of " + classSimpleName + ": " + implementingClass);
} catch (ClassNotFoundException e) {
throw new RuntimeException(classSimpleName + " implementation class not found: " + implementingClass, e);
} catch (InstantiationException e) {
throw new RuntimeException(classSimpleName + " implementation not able to be instantiated: " + implementingClass, e);
} catch (IllegalAccessException e) {
throw new RuntimeException(classSimpleName + " implementation not able to be accessed: " + implementingClass, e);
}
else
return null;
}
}

View File

@@ -1,57 +0,0 @@
package rx.subjects;
import java.util.concurrent.ConcurrentHashMap;
import rx.Observable;
import rx.Observer;
import rx.Subscription;
import rx.util.AtomicObservableSubscription;
import rx.util.SynchronizedObserver;
import rx.util.functions.Func1;
public class Subject<T> extends Observable<T> implements Observer<T> {
public static <T> Subject<T> create() {
final ConcurrentHashMap<Subscription, Observer<T>> observers = new ConcurrentHashMap<>();
Func1<Observer<T>, Subscription> onSubscribe = observer -> {
final AtomicObservableSubscription subscription = new AtomicObservableSubscription();
subscription.wrap(() -> {
// on unsubscribe remove it from the map of outbound observers to notify
observers.remove(subscription);
});
// on subscribe add it to the map of outbound observers to notify
observers.put(subscription, new SynchronizedObserver<>(observer, subscription));
return subscription;
};
return new Subject<>(onSubscribe, observers);
}
private final ConcurrentHashMap<Subscription, Observer<T>> observers;
protected Subject(Func1<Observer<T>, Subscription> onSubscribe, ConcurrentHashMap<Subscription, Observer<T>> observers) {
super(onSubscribe);
this.observers = observers;
}
@Override
public void onCompleted() {
for (Observer<T> observer : observers.values())
observer.onCompleted();
}
@Override
public void onError(Exception e) {
for (Observer<T> observer : observers.values())
observer.onError(e);
}
@Override
public void onNext(T args) {
for (Observer<T> observer : observers.values())
observer.onNext(args);
}
}

View File

@@ -1,28 +0,0 @@
package rx.subscriptions;
import java.util.concurrent.atomic.AtomicBoolean;
import rx.Observable;
import rx.Subscription;
/**
* Subscription that can be checked for status such as in a loop inside an
* {@link Observable} to exit the loop if unsubscribed.
*
* @see Rx.Net equivalent BooleanDisposable at
* http://msdn.microsoft.com/en-us/library/system.reactive.disposables.booleandisposable(v=vs.103).aspx
*/
public class BooleanSubscription implements Subscription {
private final AtomicBoolean unsubscribed = new AtomicBoolean(false);
public boolean isUnsubscribed() {
return unsubscribed.get();
}
@Override
public void unsubscribe() {
unsubscribed.set(true);
}
}

View File

@@ -1,45 +0,0 @@
package rx.subscriptions;
import rx.Subscription;
import rx.util.functions.Action0;
import rx.util.functions.FuncN;
import rx.util.functions.Functions;
public class Subscriptions {
/**
* A {@link Subscription} that does nothing.
*
* @return {@link Subscription}
*/
public static Subscription empty() {
return EMPTY;
}
/**
* A {@link Subscription} implemented via a Func
*
* @return {@link Subscription}
*/
public static Subscription create(final Action0 unsubscribe) {
return unsubscribe::call;
}
/**
* A {@link Subscription} implemented via an anonymous function (such as
* closures from other languages).
*
* @return {@link Subscription}
*/
public static Subscription create(final Object unsubscribe) {
final FuncN<?> f = Functions.from(unsubscribe);
return f::call;
}
/**
* A {@link Subscription} that does nothing when its unsubscribe method is
* called.
*/
private static final Subscription EMPTY = () -> {
};
}

View File

@@ -1,78 +0,0 @@
/**
* Copyright 2013 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.util;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import rx.Subscription;
/**
* Thread-safe wrapper around Observable Subscription that ensures unsubscribe
* can be called only once.
* <p>
* Also used to:
* <p>
* <ul>
* <li>allow the AtomicObserver to have access to the subscription in
* asynchronous execution for checking if unsubscribed occurred without
* onComplete/onError.</li>
* <li>handle both synchronous and asynchronous subscribe() execution flows</li>
* </ul>
*/
public final class AtomicObservableSubscription implements Subscription {
private final AtomicReference<Subscription> actualSubscription = new AtomicReference<>();
private final AtomicBoolean unsubscribed = new AtomicBoolean(false);
public AtomicObservableSubscription() {
}
public AtomicObservableSubscription(Subscription actualSubscription) {
this.actualSubscription.set(actualSubscription);
}
/**
* Wraps the actual subscription once it exists (if it wasn't available when
* constructed)
*
* @param actualSubscription
*
* @throws IllegalStateException if trying to set more than once (or use
* this method after setting via constructor)
*/
public AtomicObservableSubscription wrap(Subscription actualSubscription) {
if (!this.actualSubscription.compareAndSet(null, actualSubscription))
throw new IllegalStateException("Can not set subscription more than once.");
return this;
}
@Override
public void unsubscribe() {
// get the real thing and set to null in an atomic operation so we will only ever call unsubscribe once
Subscription actual = actualSubscription.getAndSet(null);
// if it's not null we will unsubscribe
if (actual != null) {
actual.unsubscribe();
unsubscribed.set(true);
}
}
public boolean isUnsubscribed() {
return unsubscribed.get();
}
}

View File

@@ -1,101 +0,0 @@
package rx.util;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicBoolean;
import rx.Observer;
import rx.plugins.RxJavaPlugins;
/**
* Wrapper around Observer to ensure compliance with Rx contract.
* <p>
* The following is taken from the Rx Design Guidelines document:
* http://go.microsoft.com/fwlink/?LinkID=205219
* <pre>
* Messages sent to instances of the IObserver interface follow the following grammar:
*
* OnNext* (OnCompleted | OnError)?
*
* This grammar allows observable sequences to send any amount (0 or more) of OnNext messages to the subscribed
* observer instance, optionally followed by a single success (OnCompleted) or failure (OnError) message.
*
* The single message indicating that an observable sequence has finished ensures that consumers of the observable
* sequence can deterministically establish that it is safe to perform cleanup operations.
*
* A single failure further ensures that abort semantics can be maintained for operators that work on
* multiple observable sequences (see paragraph 6.6).
* </pre>
*
* <p>
* This wrapper will do the following:
* <ul>
* <li>Allow only single execution of either onError or onCompleted.</li>
* <li>Once an onComplete or onError are performed, no further calls can be
* executed</li>
* <li>If unsubscribe is called, this means we call completed() and don't allow
* any further onNext calls.</li>
* <li>When onError or onComplete occur it will unsubscribe from the Observable
* (if executing asynchronously).</li>
* </ul>
* <p>
* It will not synchronize onNext execution. Use the
* {@link SynchronizedObserver} to do that.
*
* @param <T>
*/
public class AtomicObserver<T> implements Observer<T> {
private final Observer<T> actual;
private final AtomicBoolean isFinished = new AtomicBoolean(false);
private final AtomicObservableSubscription subscription;
public AtomicObserver(AtomicObservableSubscription subscription, Observer<T> actual) {
this.subscription = subscription;
this.actual = actual;
}
@Override
public void onCompleted() {
if (isFinished.compareAndSet(false, true)) {
try {
actual.onCompleted();
} catch (Exception e) {
// handle errors if the onCompleted implementation fails, not just if the Observable fails
onError(e);
}
// auto-unsubscribe
subscription.unsubscribe();
}
}
@Override
public void onError(Exception e) {
if (isFinished.compareAndSet(false, true)) {
try {
actual.onError(e);
} catch (Exception e2) {
// if the onError itself fails then pass to the plugin
// see https://github.com/Netflix/RxJava/issues/216 for further discussion
RxJavaPlugins.getInstance().getErrorHandler().handleError(e);
RxJavaPlugins.getInstance().getErrorHandler().handleError(e2);
// and throw exception despite that not being proper for Rx
// https://github.com/Netflix/RxJava/issues/198
throw new RuntimeException("Error occurred when trying to propagate error to Observer.onError", new CompositeException(Arrays.asList(e, e2)));
}
// auto-unsubscribe
subscription.unsubscribe();
}
}
@Override
public void onNext(T args) {
try {
if (!isFinished.get())
actual.onNext(args);
} catch (Exception e) {
// handle errors if the onNext implementation fails, not just if the Observable fails
onError(e);
}
}
}

View File

@@ -1,64 +0,0 @@
/**
* Copyright 2013 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.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* Exception that is a composite of 1 or more other exceptions.
* <p>
* The <code>getMessage()</code> will return a concatenation of the composite
* exceptions.
*/
public class CompositeException extends RuntimeException {
private static final long serialVersionUID = 3026362227162912146L;
private final List<Exception> exceptions;
private final String message;
public CompositeException(String messagePrefix, Collection<Exception> errors) {
StringBuilder _message = new StringBuilder();
if (messagePrefix != null)
_message.append(messagePrefix).append(" => ");
List<Exception> _exceptions = new ArrayList<>();
for (Exception e : errors) {
_exceptions.add(e);
if (_message.length() > 0)
_message.append(", ");
_message.append(e.getClass().getSimpleName()).append(":").append(e.getMessage());
}
this.exceptions = Collections.unmodifiableList(_exceptions);
this.message = _message.toString();
}
public CompositeException(Collection<Exception> errors) {
this(null, errors);
}
public List<Exception> getExceptions() {
return exceptions;
}
@Override
public String getMessage() {
return message;
}
}

View File

@@ -1,31 +0,0 @@
/**
* Copyright 2013 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.util;
public class Exceptions {
private Exceptions() {
}
public static RuntimeException propagate(Throwable t) {
if (t instanceof RuntimeException)
throw (RuntimeException) t;
else
throw new RuntimeException(t);
}
}

View File

@@ -1,75 +0,0 @@
/**
* Copyright 2013 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.util;
import java.util.Iterator;
import java.util.NoSuchElementException;
public final class Range implements Iterable<Integer> {
private final int start;
private final int end;
private final int step;
public static Range createWithCount(int start, int count) {
return create(start, start + count);
}
public static Range create(int start, int end) {
return new Range(start, end, 1);
}
public static Range createWithStep(int start, int end, int step) {
return new Range(start, end, step);
}
private Range(int start, int end, int step) {
this.start = start;
this.end = end;
this.step = step;
}
@Override
public Iterator<Integer> iterator() {
return new Iterator<Integer>() {
private int current = start;
@Override
public boolean hasNext() {
return current < end;
}
@Override
public Integer next() {
if (!hasNext())
throw new NoSuchElementException("No more elements");
int result = current;
current += step;
return result;
}
@Override
public void remove() {
throw new UnsupportedOperationException("Read only iterator");
}
};
}
@Override
public String toString() {
return "Range (" + start + ", " + end + "), step " + step;
}
}

View File

@@ -1,109 +0,0 @@
/**
* Copyright 2013 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.util;
import rx.Observer;
/**
* A thread-safe Observer for transitioning states in operators.
* <p>
* Execution rules are:
* <ul>
* <li>Allow only single-threaded, synchronous, ordered execution of onNext,
* onCompleted, onError</li>
* <li>Once an onComplete or onError are performed, no further calls can be
* executed</li>
* <li>If unsubscribe is called, this means we call completed() and don't allow
* any further onNext calls.</li>
* </ul>
*
* @param <T>
*/
public final class SynchronizedObserver<T> implements Observer<T> {
/**
* Intrinsic synchronized locking with double-check short-circuiting was
* chosen after testing several other implementations.
*
* The code and results can be found here: -
* https://github.com/benjchristensen/JavaLockPerformanceTests/tree/master/results/Observer
* -
* https://github.com/benjchristensen/JavaLockPerformanceTests/tree/master/src/com/benjchristensen/performance/locks/Observer
*
* The major characteristic that made me choose synchronized instead of
* Reentrant or a customer AbstractQueueSynchronizer implementation is that
* intrinsic locking performed better when nested, and AtomicObserver will
* end up nested most of the time since Rx is compositional by its very
* nature.
*
* // TODO composing of this class should rarely happen now with updated
* design so this decision should be revisited
*/
private final Observer<T> observer;
private final AtomicObservableSubscription subscription;
private volatile boolean finishRequested = false;
private volatile boolean finished = false;
public SynchronizedObserver(Observer<T> Observer, AtomicObservableSubscription subscription) {
this.observer = Observer;
this.subscription = subscription;
}
@Override
public void onNext(T arg) {
if (finished || finishRequested || subscription.isUnsubscribed())
// if we're already stopped, or a finish request has been received, we won't allow further onNext requests
return;
synchronized (this) {
// check again since this could have changed while waiting
if (finished || finishRequested || subscription.isUnsubscribed())
// if we're already stopped, or a finish request has been received, we won't allow further onNext requests
return;
observer.onNext(arg);
}
}
@Override
public void onError(Exception e) {
if (finished || subscription.isUnsubscribed())
// another thread has already finished us, so we won't proceed
return;
finishRequested = true;
synchronized (this) {
// check again since this could have changed while waiting
if (finished || subscription.isUnsubscribed())
return;
observer.onError(e);
finished = true;
}
}
@Override
public void onCompleted() {
if (finished || subscription.isUnsubscribed())
// another thread has already finished us, so we won't proceed
return;
finishRequested = true;
synchronized (this) {
// check again since this could have changed while waiting
if (finished || subscription.isUnsubscribed())
return;
observer.onCompleted();
finished = true;
}
}
}

View File

@@ -1,21 +0,0 @@
/**
* Copyright 2013 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.util.functions;
public interface Action0 extends Function {
public void call();
}

View File

@@ -1,21 +0,0 @@
/**
* Copyright 2013 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.util.functions;
public interface Action1<T1> extends Function {
public void call(T1 t1);
}

View File

@@ -1,21 +0,0 @@
/**
* Copyright 2013 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.util.functions;
public interface Action2<T1, T2> extends Function {
public void call(T1 t1, T2 t2);
}

View File

@@ -1,21 +0,0 @@
/**
* Copyright 2013 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.util.functions;
public interface Action3<T1, T2, T3> extends Function {
public void call(T1 t1, T2 t2, T3 t3);
}

View File

@@ -1,21 +0,0 @@
/**
* Copyright 2013 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.util.functions;
public interface Func0<R> extends Function {
public R call();
}

View File

@@ -1,21 +0,0 @@
/**
* Copyright 2013 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.util.functions;
public interface Func1<T1, R> extends Function {
public R call(T1 t1);
}

View File

@@ -1,21 +0,0 @@
/**
* Copyright 2013 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.util.functions;
public interface Func2<T1, T2, R> extends Function {
public R call(T1 t1, T2 t2);
}

View File

@@ -1,21 +0,0 @@
/**
* Copyright 2013 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.util.functions;
public interface Func3<T1, T2, T3, R> extends Function {
public R call(T1 t1, T2 t2, T3 t3);
}

View File

@@ -1,21 +0,0 @@
/**
* Copyright 2013 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.util.functions;
public interface Func4<T1, T2, T3, T4, R> extends Function {
public R call(T1 t1, T2 t2, T3 t3, T4 t4);
}

View File

@@ -1,21 +0,0 @@
/**
* Copyright 2013 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.util.functions;
public interface Func5<T1, T2, T3, T4, T5, R> extends Function {
public R call(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5);
}

View File

@@ -1,21 +0,0 @@
/**
* Copyright 2013 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.util.functions;
public interface Func6<T1, T2, T3, T4, T5, T6, R> extends Function {
public R call(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6);
}

View File

@@ -1,21 +0,0 @@
/**
* Copyright 2013 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.util.functions;
public interface Func7<T1, T2, T3, T4, T5, T6, T7, R> extends Function {
public R call(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7);
}

View File

@@ -1,21 +0,0 @@
/**
* Copyright 2013 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.util.functions;
public interface Func8<T1, T2, T3, T4, T5, T6, T7, T8, R> extends Function {
public R call(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8);
}

View File

@@ -1,21 +0,0 @@
/**
* Copyright 2013 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.util.functions;
public interface Func9<T1, T2, T3, T4, T5, T6, T7, T8, T9, R> extends Function {
public R call(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9);
}

View File

@@ -1,21 +0,0 @@
/**
* Copyright 2013 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.util.functions;
public interface FuncN<R> extends Function {
public R call(Object... args);
}

View File

@@ -1,10 +0,0 @@
package rx.util.functions;
/**
* All Func and Action interfaces extend from this.
* <p>
* Marker interface to allow isntanceof checks.
*/
public interface Function {
}

View File

@@ -1,40 +0,0 @@
/**
* Copyright 2013 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.util.functions;
public interface FunctionLanguageAdaptor {
/**
* Invoke the function and return the results.
*
* @param function
* @param args
*
* @return Object results from function execution
*/
Object call(Object function, Object[] args);
/**
* The Class of the Function that this adaptor serves.
* <p>
* Example: groovy.lang.Closure
* <p>
* This should not return classes of java.* packages.
*
* @return Class[] of classes that this adaptor should be invoked for.
*/
public Class<?>[] getFunctionClass();
}

View File

@@ -1,503 +0,0 @@
/**
* Copyright 2013 Netflix, Inc.
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.util.functions;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
import org.jackhuang.hellominecraft.utils.logging.logger.Logger;
/**
* Allows execution of functions from multiple different languages.
* <p>
* Language support is provided via implementations of
* {@link FunctionLanguageAdaptor}.
* <p>
* This class will dynamically look for known language adaptors on the classpath
* at startup or new ones can be registered using
* {@link #registerLanguageAdaptor(Class[], FunctionLanguageAdaptor)}.
*/
public class Functions {
private static final Logger logger = new Logger("Functions");
private final static ConcurrentHashMap<Class<?>, FunctionLanguageAdaptor> languageAdaptors = new ConcurrentHashMap<>();
private static boolean loadLanguageAdaptor(String name) {
String className = "rx.lang." + name.toLowerCase() + "." + name + "Adaptor";
try {
Class<?> c = Class.forName(className);
FunctionLanguageAdaptor a = (FunctionLanguageAdaptor) c.newInstance();
registerLanguageAdaptor(a.getFunctionClass(), a);
logger.info("Successfully loaded function language adaptor: " + name + " with path: " + className);
} catch (ClassNotFoundException e) {
logger.info("Could not find function language adaptor: " + name + " with path: " + className);
return false;
} catch (Exception e) {
logger.error("Failed trying to initialize function language adaptor: " + className, e);
return false;
}
return true;
}
public static void registerLanguageAdaptor(Class<?>[] functionClasses, FunctionLanguageAdaptor adaptor) {
for (Class<?> functionClass : functionClasses) {
if (functionClass.getPackage().getName().startsWith("java."))
throw new IllegalArgumentException("FunctionLanguageAdaptor implementations can not specify java.lang.* classes.");
languageAdaptors.put(functionClass, adaptor);
}
}
public static void removeLanguageAdaptor(Class<?> functionClass) {
languageAdaptors.remove(functionClass);
}
public static Collection<FunctionLanguageAdaptor> getRegisteredLanguageAdaptors() {
return languageAdaptors.values();
}
/**
* Utility method for determining the type of closure/function and executing
* it.
*
* @param function
*/
@SuppressWarnings({ "rawtypes" })
public static FuncN from(final Object function) {
if (function == null)
throw new RuntimeException("function is null. Can't send arguments to null function.");
/*
* check for typed Rx Function implementation first
*/
if (function instanceof Function)
return fromFunction((Function) function);
else
/*
* not an Rx Function so try language adaptors
*/
// check for language adaptor
for (final Class c : languageAdaptors.keySet())
if (c.isInstance(function)) {
final FunctionLanguageAdaptor la = languageAdaptors.get(c);
// found the language adaptor so wrap in FuncN and return
return new FuncN() {
@Override
public Object call(Object... args) {
return la.call(function, args);
}
};
} // no language adaptor found
// no support found
throw new RuntimeException("Unsupported closure type: " + function.getClass().getSimpleName());
}
//
// @SuppressWarnings("unchecked")
// private static <R> R executionRxFunction(Function function, Object... args) {
// // check Func* classes
// if (function instanceof Func0) {
// Func0<R> f = (Func0<R>) function;
// if (args.length != 0) {
// throw new RuntimeException("The closure was Func0 and expected no arguments, but we received: " + args.length);
// }
// return (R) f.call();
// } else if (function instanceof Func1) {
// Func1<Object, R> f = (Func1<Object, R>) function;
// if (args.length != 1) {
// throw new RuntimeException("The closure was Func1 and expected 1 argument, but we received: " + args.length);
// }
// return f.call(args[0]);
// } else if (function instanceof Func2) {
// Func2<Object, Object, R> f = (Func2<Object, Object, R>) function;
// if (args.length != 2) {
// throw new RuntimeException("The closure was Func2 and expected 2 arguments, but we received: " + args.length);
// }
// return f.call(args[0], args[1]);
// } else if (function instanceof Func3) {
// Func3<Object, Object, Object, R> f = (Func3<Object, Object, Object, R>) function;
// if (args.length != 3) {
// throw new RuntimeException("The closure was Func3 and expected 3 arguments, but we received: " + args.length);
// }
// return (R) f.call(args[0], args[1], args[2]);
// } else if (function instanceof Func4) {
// Func4<Object, Object, Object, Object, R> f = (Func4<Object, Object, Object, Object, R>) function;
// if (args.length != 1) {
// throw new RuntimeException("The closure was Func4 and expected 4 arguments, but we received: " + args.length);
// }
// return f.call(args[0], args[1], args[2], args[3]);
// } else if (function instanceof Func5) {
// Func5<Object, Object, Object, Object, Object, R> f = (Func5<Object, Object, Object, Object, Object, R>) function;
// if (args.length != 1) {
// throw new RuntimeException("The closure was Func5 and expected 5 arguments, but we received: " + args.length);
// }
// return f.call(args[0], args[1], args[2], args[3], args[4]);
// } else if (function instanceof Func6) {
// Func6<Object, Object, Object, Object, Object, Object, R> f = (Func6<Object, Object, Object, Object, Object, Object, R>) function;
// if (args.length != 1) {
// throw new RuntimeException("The closure was Func6 and expected 6 arguments, but we received: " + args.length);
// }
// return f.call(args[0], args[1], args[2], args[3], args[4], args[5]);
// } else if (function instanceof Func7) {
// Func7<Object, Object, Object, Object, Object, Object, Object, R> f = (Func7<Object, Object, Object, Object, Object, Object, Object, R>) function;
// if (args.length != 1) {
// throw new RuntimeException("The closure was Func7 and expected 7 arguments, but we received: " + args.length);
// }
// return f.call(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
// } else if (function instanceof Func8) {
// Func8<Object, Object, Object, Object, Object, Object, Object, Object, R> f = (Func8<Object, Object, Object, Object, Object, Object, Object, Object, R>) function;
// if (args.length != 1) {
// throw new RuntimeException("The closure was Func8 and expected 8 arguments, but we received: " + args.length);
// }
// return f.call(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
// } else if (function instanceof Func9) {
// Func9<Object, Object, Object, Object, Object, Object, Object, Object, Object, R> f = (Func9<Object, Object, Object, Object, Object, Object, Object, Object, Object, R>) function;
// if (args.length != 1) {
// throw new RuntimeException("The closure was Func9 and expected 9 arguments, but we received: " + args.length);
// }
// return f.call(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
// } else if (function instanceof FuncN) {
// FuncN<R> f = (FuncN<R>) function;
// return f.call(args);
// } else if (function instanceof Action0) {
// Action0 f = (Action0) function;
// if (args.length != 1) {
// throw new RuntimeException("The closure was Action0 and expected 0 arguments, but we received: " + args.length);
// }
// f.call();
// return null;
// } else if (function instanceof Action1) {
// Action1<Object> f = (Action1<Object>) function;
// if (args.length != 1) {
// throw new RuntimeException("The closure was Action1 and expected 1 argument, but we received: " + args.length);
// }
// f.call(args[0]);
// return null;
// } else if (function instanceof Action2) {
// Action2<Object, Object> f = (Action2<Object, Object>) function;
// if (args.length != 1) {
// throw new RuntimeException("The closure was Action2 and expected 2 argument, but we received: " + args.length);
// }
// f.call(args[0], args[1]);
// return null;
// } else if (function instanceof Action3) {
// Action3<Object, Object, Object> f = (Action3<Object, Object, Object>) function;
// if (args.length != 1) {
// throw new RuntimeException("The closure was Action1 and expected 1 argument, but we received: " + args.length);
// }
// f.call(args[0], args[1], args[2]);
// return null;
// }
//
// throw new RuntimeException("Unknown implementation of Function: " + function.getClass().getSimpleName());
// }
@SuppressWarnings({ "unchecked", "rawtypes" })
private static FuncN fromFunction(Function function) {
// check Func* classes
if (function instanceof Func0)
return fromFunc((Func0) function);
else if (function instanceof Func1)
return fromFunc((Func1) function);
else if (function instanceof Func2)
return fromFunc((Func2) function);
else if (function instanceof Func3)
return fromFunc((Func3) function);
else if (function instanceof Func4)
return fromFunc((Func4) function);
else if (function instanceof Func5)
return fromFunc((Func5) function);
else if (function instanceof Func6)
return fromFunc((Func6) function);
else if (function instanceof Func7)
return fromFunc((Func7) function);
else if (function instanceof Func8)
return fromFunc((Func8) function);
else if (function instanceof Func9)
return fromFunc((Func9) function);
else if (function instanceof FuncN)
return (FuncN) function;
else if (function instanceof Action0)
return fromAction((Action0) function);
else if (function instanceof Action1)
return fromAction((Action1) function);
else if (function instanceof Action2)
return fromAction((Action2) function);
else if (function instanceof Action3)
return fromAction((Action3) function);
throw new RuntimeException("Unknown implementation of Function: " + function.getClass().getSimpleName());
}
/**
* Convert a function to FuncN to allow heterogeneous handling of functions
* with different arities.
*
* @param f
*
* @return {@link FuncN}
*/
public static <R> FuncN<R> fromFunc(final Func0<R> f) {
return (Object... args) -> {
if (args.length != 0)
throw new RuntimeException("Func0 expecting 0 arguments.");
return f.call();
};
}
/**
* Convert a function to FuncN to allow heterogeneous handling of functions
* with different arities.
*
* @param f
*
* @return {@link FuncN}
*/
public static <T0, R> FuncN<R> fromFunc(final Func1<T0, R> f) {
return (Object... args) -> {
if (args.length != 1)
throw new RuntimeException("Func1 expecting 1 argument.");
return f.call((T0) args[0]);
};
}
/**
* Convert a function to FuncN to allow heterogeneous handling of functions
* with different arities.
*
* @param f
*
* @return {@link FuncN}
*/
public static <T0, T1, R> FuncN<R> fromFunc(final Func2<T0, T1, R> f) {
return (Object... args) -> {
if (args.length != 2)
throw new RuntimeException("Func2 expecting 2 arguments.");
return f.call((T0) args[0], (T1) args[1]);
};
}
/**
* Convert a function to FuncN to allow heterogeneous handling of functions
* with different arities.
*
* @param f
*
* @return {@link FuncN}
*/
public static <T0, T1, T2, R> FuncN<R> fromFunc(final Func3<T0, T1, T2, R> f) {
return (Object... args) -> {
if (args.length != 3)
throw new RuntimeException("Func3 expecting 3 arguments.");
return f.call((T0) args[0], (T1) args[1], (T2) args[2]);
};
}
/**
* Convert a function to FuncN to allow heterogeneous handling of functions
* with different arities.
*
* @param f
*
* @return {@link FuncN}
*/
public static <T0, T1, T2, T3, R> FuncN<R> fromFunc(final Func4<T0, T1, T2, T3, R> f) {
return (Object... args) -> {
if (args.length != 4)
throw new RuntimeException("Func4 expecting 4 arguments.");
return f.call((T0) args[0], (T1) args[1], (T2) args[2], (T3) args[3]);
};
}
/**
* Convert a function to FuncN to allow heterogeneous handling of functions
* with different arities.
*
* @param f
*
* @return {@link FuncN}
*/
public static <T0, T1, T2, T3, T4, R> FuncN<R> fromFunc(final Func5<T0, T1, T2, T3, T4, R> f) {
return (Object... args) -> {
if (args.length != 5)
throw new RuntimeException("Func5 expecting 5 arguments.");
return f.call((T0) args[0], (T1) args[1], (T2) args[2], (T3) args[3], (T4) args[4]);
};
}
/**
* Convert a function to FuncN to allow heterogeneous handling of functions
* with different arities.
*
* @param f
*
* @return {@link FuncN}
*/
public static <T0, T1, T2, T3, T4, T5, R> FuncN<R> fromFunc(final Func6<T0, T1, T2, T3, T4, T5, R> f) {
return (Object... args) -> {
if (args.length != 6)
throw new RuntimeException("Func6 expecting 6 arguments.");
return f.call((T0) args[0], (T1) args[1], (T2) args[2], (T3) args[3], (T4) args[4], (T5) args[5]);
};
}
/**
* Convert a function to FuncN to allow heterogeneous handling of functions
* with different arities.
*
* @param f
*
* @return {@link FuncN}
*/
public static <T0, T1, T2, T3, T4, T5, T6, R> FuncN<R> fromFunc(final Func7<T0, T1, T2, T3, T4, T5, T6, R> f) {
return (Object... args) -> {
if (args.length != 7)
throw new RuntimeException("Func7 expecting 7 arguments.");
return f.call((T0) args[0], (T1) args[1], (T2) args[2], (T3) args[3], (T4) args[4], (T5) args[5], (T6) args[6]);
};
}
/**
* Convert a function to FuncN to allow heterogeneous handling of functions
* with different arities.
*
* @param f
*
* @return {@link FuncN}
*/
public static <T0, T1, T2, T3, T4, T5, T6, T7, R> FuncN<R> fromFunc(final Func8<T0, T1, T2, T3, T4, T5, T6, T7, R> f) {
return (Object... args) -> {
if (args.length != 8)
throw new RuntimeException("Func8 expecting 8 arguments.");
return f.call((T0) args[0], (T1) args[1], (T2) args[2], (T3) args[3], (T4) args[4], (T5) args[5], (T6) args[6], (T7) args[7]);
};
}
/**
* Convert a function to FuncN to allow heterogeneous handling of functions
* with different arities.
*
* @param f
*
* @return {@link FuncN}
*/
public static <T0, T1, T2, T3, T4, T5, T6, T7, T8, R> FuncN<R> fromFunc(final Func9<T0, T1, T2, T3, T4, T5, T6, T7, T8, R> f) {
return (Object... args) -> {
if (args.length != 9)
throw new RuntimeException("Func9 expecting 9 arguments.");
return f.call((T0) args[0], (T1) args[1], (T2) args[2], (T3) args[3], (T4) args[4], (T5) args[5], (T6) args[6], (T7) args[7], (T8) args[8]);
};
}
/**
* Convert a function to FuncN to allow heterogeneous handling of functions
* with different arities.
*
* @param f
*
* @return {@link FuncN}
*/
public static FuncN<Void> fromAction(final Action0 f) {
return (Object... args) -> {
if (args.length != 0)
throw new RuntimeException("Action0 expecting 0 arguments.");
f.call();
return null;
};
}
/**
* Convert a function to FuncN to allow heterogeneous handling of functions
* with different arities.
*
* @param f
*
* @return {@link FuncN}
*/
public static <T0> FuncN<Void> fromAction(final Action1<T0> f) {
return (Object... args) -> {
if (args.length != 1)
throw new RuntimeException("Action1 expecting 1 argument.");
f.call((T0) args[0]);
return null;
};
}
/**
* Convert a function to FuncN to allow heterogeneous handling of functions
* with different arities.
*
* @param f
*
* @return {@link FuncN}
*/
public static <T0, T1> FuncN<Void> fromAction(final Action2<T0, T1> f) {
return (Object... args) -> {
if (args.length != 2)
throw new RuntimeException("Action3 expecting 2 arguments.");
f.call((T0) args[0], (T1) args[1]);
return null;
};
}
/**
* Convert a function to FuncN to allow heterogeneous handling of functions
* with different arities.
*
* @param f
*
* @return {@link FuncN}
*/
public static <T0, T1, T2> FuncN<Void> fromAction(final Action3<T0, T1, T2> f) {
return (Object... args) -> {
if (args.length != 3)
throw new RuntimeException("Action3 expecting 3 arguments.");
f.call((T0) args[0], (T1) args[1], (T2) args[2]);
return null;
};
}
@SuppressWarnings("unchecked")
public static <T> Func1<T, Boolean> alwaysTrue() {
return (Func1<T, Boolean>) AlwaysTrue.INSTANCE;
}
@SuppressWarnings("unchecked")
public static <T> Func1<T, T> identity() {
return (Func1<T, T>) Identity.INSTANCE;
}
private enum AlwaysTrue implements Func1<Object, Boolean> {
INSTANCE;
@Override
public Boolean call(Object o) {
return true;
}
}
private enum Identity implements Func1<Object, Object> {
INSTANCE;
@Override
public Object call(Object o) {
return o;
}
}
}

View File

@@ -260,7 +260,7 @@ mainwindow.enter_script_name=\u8f93\u5165\u8981\u751f\u6210\u811a\u672c\u7684\u6
mainwindow.make_launch_succeed=\u542f\u52a8\u811a\u672c\u5df2\u751f\u6210\u5b8c\u6bd5:
mainwindow.no_version=\u672a\u627e\u5230\u4efb\u4f55\u7248\u672c\uff0c\u662f\u5426\u8fdb\u5165\u6e38\u620f\u4e0b\u8f7d\uff1f
launcher.about=<html>\u9ed8\u8ba4\u80cc\u666f\u56fe\u6765\u81eaLiberty Dome\u670d\u52a1\u5668\u3002<br/>\u5173\u4e8e\u4f5c\u8005\uff1a<br/>\n\u767e\u5ea6ID\uff1ahuanghongxun20<br/>\nmcbbs\uff1ahuanghongxun<br/>\n\u90ae\u7bb1\uff1ahuanghongxun2008@126.com<br/>\nMinecraft Forum ID: klkl6523<br/>\n\u6b22\u8fce\u63d0\u4ea4Bug\u54e6<br/>\nCopyright (c) 2013-2015 huangyuhui.<br/>\u514d\u8d23\u58f0\u660e\uff1aMinecraft\u8f6f\u4ef6\u7248\u6743\u5f52Mojang AB\u6240\u6709\uff0c\u6e38\u620f\u7531\u4e8e\u8bef\u64cd\u4f5c\u672c\u542f\u52a8\u5668\u800c\u4e22\u5931\u6570\u636e\u7684\u6982\u4e0d\u8d1f\u8d23\u3002<br/>\u672c\u542f\u52a8\u5668\u5728GPLv3\u534f\u8bae\u4e0b\u5f00\u6e90:https://github.com/huanghongxun/HMCL/<br/>\u672c\u8f6f\u4ef6\u4f7f\u7528\u4e86\u57fa\u4e8eApache License 2.0\u7684RxJava\u548cGson\u9879\u76ee\uff0c\u611f\u8c22\u8d21\u732e\u8005\u3002</html>
launcher.about=<html>\u9ed8\u8ba4\u80cc\u666f\u56fe\u6765\u81eaLiberty Dome\u670d\u52a1\u5668\u3002<br/>\u5173\u4e8e\u4f5c\u8005\uff1a<br/>\n\u767e\u5ea6ID\uff1ahuanghongxun20<br/>\nmcbbs\uff1ahuanghongxun<br/>\n\u90ae\u7bb1\uff1ahuanghongxun2008@126.com<br/>\nMinecraft Forum ID: klkl6523<br/>\n\u6b22\u8fce\u63d0\u4ea4Bug\u54e6<br/>\nCopyright (c) 2013-2015 huangyuhui.<br/>\u514d\u8d23\u58f0\u660e\uff1aMinecraft\u8f6f\u4ef6\u7248\u6743\u5f52Mojang AB\u6240\u6709\uff0c\u6e38\u620f\u7531\u4e8e\u8bef\u64cd\u4f5c\u672c\u542f\u52a8\u5668\u800c\u4e22\u5931\u6570\u636e\u7684\u6982\u4e0d\u8d1f\u8d23\u3002<br/>\u672c\u542f\u52a8\u5668\u5728GPLv3\u534f\u8bae\u4e0b\u5f00\u6e90:https://github.com/huanghongxun/HMCL/<br/>\u672c\u8f6f\u4ef6\u4f7f\u7528\u4e86\u57fa\u4e8eApache License 2.0\u7684Gson\u9879\u76ee\uff0c\u611f\u8c22\u8d21\u732e\u8005\u3002</html>
launcher.download_source=\u4e0b\u8f7d\u6e90
launcher.background_location=\u80cc\u666f\u5730\u5740
launcher.exit_failed=\u5f3a\u5236\u9000\u51fa\u5931\u8d25\uff0c\u53ef\u80fd\u662fForge 1.7.10\u53ca\u66f4\u9ad8\u7248\u672c\u5bfc\u81f4\u7684\uff0c\u65e0\u6cd5\u89e3\u51b3\u3002

View File

@@ -260,7 +260,7 @@ mainwindow.enter_script_name=Enter the script name.
mainwindow.make_launch_succeed=Finished script creation.
mainwindow.no_version=No version found. Switch to Game Downloads Tab?
launcher.about=<html>About Author<br/>\nEmail\uff1ahuanghongxun2008@126.com<br/>\nMinecraft Forum ID: klkl6523<br/>\nCopyright (c) 2013 huangyuhui<br/>Opened source under GPL v3 license:http://github.com/huanghongxun/HMCL/<br/>This software used project RxJava and Gson which is under Apache License 2.0, thanks contributors.</html>
launcher.about=<html>About Author<br/>\nEmail\uff1ahuanghongxun2008@126.com<br/>\nMinecraft Forum ID: klkl6523<br/>\nCopyright (c) 2013 huangyuhui<br/>Opened source under GPL v3 license:http://github.com/huanghongxun/HMCL/<br/>This software used project Gson which is under Apache License 2.0, thanks contributors.</html>
launcher.download_source=Download Source
launcher.background_location=Background Location
launcher.exit_failed=Failed to shutdown.

View File

@@ -110,7 +110,7 @@ crash.advice.ConcurrentModificationException=\u9019\u53ef\u80fd\u662f\u56e0\u70b
crash.advice.ClassNotFoundException=Minecraft\u4e0d\u5b8c\u6574\u6216Mod\u885d\u7a81\uff0c\u5982\u679c\u6709\u672a\u80fd\u4e0b\u8f7d\u7684\u8cc7\u6599\u8bf7\u4e0b\u8f7d\u6210\u529f\u540e\u91cd\u8bd5\u6216\u662f\u5ba2\u6237\u7aef\u635f\u574f\u8bf7\u91cd\u8bd5\u8bf7\u91cd\u65b0\u5236\u4f5c\u5ba2\u6237\u7aef\u6216\u4e0b\u8f09\u6574\u5408\u5305\u89e3\u6c7a\u554f\u984c\u3002
crash.advice.NoSuchFieldError=Minecraft\u4e0d\u5b8c\u6574\u6216Mod\u885d\u7a81\uff0c\u5982\u679c\u6709\u672a\u80fd\u4e0b\u8f7d\u7684\u8cc7\u6599\u8bf7\u4e0b\u8f7d\u6210\u529f\u540e\u91cd\u8bd5\u6216\u662f\u5ba2\u6237\u7aef\u635f\u574f\u8bf7\u91cd\u8bd5\u8bf7\u91cd\u65b0\u5236\u4f5c\u5ba2\u6237\u7aef\u6216\u4e0b\u8f09\u6574\u5408\u5305\u89e3\u6c7a\u554f\u984c\u3002
crash.advice.LWJGLException=\u60a8\u7684\u7535\u8111\u4e0d\u6b63\u5e38\uff0c\u53ef\u80fd\u9700\u8981\u4f7f\u7528\u9a71\u52a8\u7cbe\u7075\u6216\u5176\u4ed6\u5b89\u88c5\u5668\u66f4\u65b0\u663e\u5361\u9a71\u52a8\u3002
crash.advice.SecurityException=\u53ef\u80fd\u662f\u60a8\u4fee\u6539\u4e86minecraft.jar\u4f46\u672a\u522a\u9664META-INF\u8cc7\u6599\u593e\u7684\u539f\u56e0\u3002\u8acb\u901a\u904e\u58d3\u7e2e\u8edf\u4ef6\u522a\u9664jar\u4e2d\u7684META-INF\u8cc7\u6599\u593e\u3002
crash.advice.SecurityException=\u53ef\u80fd\u662f\u60a8\u4fee\u6539\u4e86minecraft.jar\u4f46\u672a\u522a\u9664META-INF\u8cc7\u6599\u593e\u7684\u539f\u56e0\u3002\u8acb\u901a\u904e\u58d3\u7e2e\u8edf\u9ad4\u522a\u9664jar\u4e2d\u7684META-INF\u8cc7\u6599\u593e\u3002
crash.advice.OutOfMemoryError=\u5185\u5b58\u6ea2\u51fa\uff0c\u60a8\u8bbe\u7f6e\u7684Minecraft\u6700\u5927\u5185\u5b58\u8fc7\u5c0f\uff0c\u8bf7\u8c03\u5927\uff01
crash.advice.otherwise=\u53ef\u80fd\u662fMod\u6216\u5176\u4ed6\u554f\u984c\u3002
@@ -119,7 +119,7 @@ crash.advice.no_lwjgl=\u53ef\u80fd\u662f\u904a\u6232\u4f9d\u8cf4\u5eab\u4e0d\u5b
crash.advice.no=\u7121\u5efa\u8b70\u3002
crash.user_fault=\u60a8\u7684\u7cfb\u7d71\u6216Java\u74b0\u5883\u53ef\u80fd\u5b89\u88dd\u4e0d\u7576\u5c0e\u81f4\u672c\u8edf\u4ef6\u5d29\u6f70\uff0c\u8acb\u6aa2\u67e5\u60a8\u7684Java\u74b0\u5883\u6216\u60a8\u7684\u96fb\u8166\uff01\u53ef\u4ee5\u5617\u8a66\u91cd\u65b0\u5b89\u88ddJava\u3002
crash.user_fault=\u60a8\u7684\u7cfb\u7d71\u6216Java\u74b0\u5883\u53ef\u80fd\u5b89\u88dd\u4e0d\u7576\u5c0e\u81f4\u672c\u8edf\u9ad4\u5d29\u6f70\uff0c\u8acb\u6aa2\u67e5\u60a8\u7684Java\u74b0\u5883\u6216\u60a8\u7684\u96fb\u8166\uff01\u53ef\u4ee5\u5617\u8a66\u91cd\u65b0\u5b89\u88ddJava\u3002
crash.headless=\u5982\u679c\u60a8\u7684\u64cd\u4f5c\u7cfb\u7d71\u662fLinux\uff0c\u8acb\u6ce8\u610f\u4e0d\u8981\u4f7f\u7528OpenJDK\uff0c\u52d9\u5fc5\u4f7f\u7528Oracle JDK\uff0c\u6216\u5617\u8a66\u6dfb\u52a0-Djava.awt.headless=false\u53c3\u6578\uff0c\u6216\u6aa2\u67e5\u60a8\u7684Xserver\u662f\u5426\u6b63\u5e38
crash.NoClassDefFound=\u8acb\u78ba\u8a8dHMCL\u672c\u9ad4\u662f\u5426\u5b8c\u6574
@@ -260,7 +260,7 @@ mainwindow.enter_script_name=\u8f38\u5165\u8981\u751f\u6210\u8173\u672c\u7684\u8
mainwindow.make_launch_succeed=\u555f\u52d5\u8173\u672c\u5df2\u751f\u6210\u5b8c\u7562:
mainwindow.no_version=\u672a\u627e\u5230\u4efb\u4f55\u7248\u672c\uff0c\u662f\u5426\u9032\u5165\u904a\u6232\u4e0b\u8f09\uff1f
launcher.about=<html>\u9ed8\u8a8d\u80cc\u666f\u5716\u4f86\u81eaLiberty Dome\u670d\u52d9\u5668\u3002 <br/>\u95dc\u65bc\u4f5c\u8005\uff1a<br/>\n\u767e\u5ea6ID\uff1ahuanghongxun20<br/>\nmcbbs\uff1ahuanghongxun<br/>\n\u90f5\u7bb1\uff1ahuanghongxun2008@126.com<br/>\nMinecraft Forum ID: klkl6523<br />\n\u6b61\u8fce\u63d0\u4ea4Bug\u54e6<br/>\nCopyright (c) 2013-2015 huangyuhui.<br/>\u514d\u8cac\u8072\u660e\uff1aMinecraft\u8edf\u4ef6\u7248\u6b0a\u6b78Mojang AB\u6240\u6709\uff0c\u904a\u6232\u7531\u65bc\u8aa4\u64cd\u4f5c\u672c\u555f\u52d5\u5668\u800c\u4e1f\u5931\u6578\u64da\u7684\u6982\u4e0d\u8ca0\u8cac\u3002 <br/>\u672c\u555f\u52d5\u5668\u5728GPLv3\u5354\u8b70\u4e0b\u958b\u6e90:http://github.com/huanghongxun/HMCL/<br/>\u672c\u8edf\u4ef6\u4f7f\u7528\u4e86\u57fa\u65bcApache License 2.0\u7684RxJava\u548cGson\u9805\u76ee\uff0c\u611f\u8b1d\u8ca2\u737b\u8005\u3002</html>
launcher.about=<html>\u9ed8\u8a8d\u80cc\u666f\u5716\u4f86\u81eaLiberty Dome\u670d\u52d9\u5668\u3002 <br/>\u95dc\u65bc\u4f5c\u8005\uff1a<br/>\n\u767e\u5ea6ID\uff1ahuanghongxun20<br/>\nmcbbs\uff1ahuanghongxun<br/>\n\u90f5\u7bb1\uff1ahuanghongxun2008@126.com<br/>\nMinecraft Forum ID: klkl6523<br />\n\u6b61\u8fce\u63d0\u4ea4Bug\u54e6<br/>\nCopyright (c) 2013-2015 huangyuhui.<br/>\u514d\u8cac\u8072\u660e\uff1aMinecraft\u8edf\u9ad4\u7248\u6b0a\u6b78Mojang AB\u6240\u6709\uff0c\u904a\u6232\u7531\u65bc\u8aa4\u64cd\u4f5c\u672c\u555f\u52d5\u5668\u800c\u4e1f\u5931\u6578\u64da\u7684\u6982\u4e0d\u8ca0\u8cac\u3002 <br/>\u672c\u555f\u52d5\u5668\u5728GPLv3\u5354\u8b70\u4e0b\u958b\u6e90:http://github.com/huanghongxun/HMCL/<br/>\u672c\u8edf\u9ad4\u4f7f\u7528\u4e86\u57fa\u65bcApache License 2.0\u7684Gson\u9805\u76ee\uff0c\u611f\u8b1d\u8ca2\u737b\u8005\u3002</html>
launcher.download_source=\u4e0b\u8f09\u6e90
launcher.background_location=\u80cc\u666f\u5730\u5740
launcher.exit_failed=\u5f37\u5236\u9000\u51fa\u5931\u6557\uff0c\u53ef\u80fd\u662fForge 1.7.10\u53ca\u66f4\u9ad8\u7248\u672c\u5c0e\u81f4\u7684\uff0c\u7121\u6cd5\u89e3\u6c7a\u3002

View File

@@ -260,7 +260,7 @@ mainwindow.enter_script_name=\u8f93\u5165\u8981\u751f\u6210\u811a\u672c\u7684\u6
mainwindow.make_launch_succeed=\u542f\u52a8\u811a\u672c\u5df2\u751f\u6210\u5b8c\u6bd5:
mainwindow.no_version=\u672a\u627e\u5230\u4efb\u4f55\u7248\u672c\uff0c\u662f\u5426\u8fdb\u5165\u6e38\u620f\u4e0b\u8f7d\uff1f
launcher.about=<html>\u9ed8\u8ba4\u80cc\u666f\u56fe\u6765\u81eaLiberty Dome\u670d\u52a1\u5668\u3002<br/>\u5173\u4e8e\u4f5c\u8005\uff1a<br/>\n\u767e\u5ea6ID\uff1ahuanghongxun20<br/>\nmcbbs\uff1ahuanghongxun<br/>\n\u90ae\u7bb1\uff1ahuanghongxun2008@126.com<br/>\nMinecraft Forum ID: klkl6523<br/>\n\u6b22\u8fce\u63d0\u4ea4Bug\u54e6<br/>\nCopyright (c) 2013-2015 huangyuhui.<br/>\u514d\u8d23\u58f0\u660e\uff1aMinecraft\u8f6f\u4ef6\u7248\u6743\u5f52Mojang AB\u6240\u6709\uff0c\u6e38\u620f\u7531\u4e8e\u8bef\u64cd\u4f5c\u672c\u542f\u52a8\u5668\u800c\u4e22\u5931\u6570\u636e\u7684\u6982\u4e0d\u8d1f\u8d23\u3002<br/>\u672c\u542f\u52a8\u5668\u5728GPLv3\u534f\u8bae\u4e0b\u5f00\u6e90:https://github.com/huanghongxun/HMCL/<br/>\u672c\u8f6f\u4ef6\u4f7f\u7528\u4e86\u57fa\u4e8eApache License 2.0\u7684RxJava\u548cGson\u9879\u76ee\uff0c\u611f\u8c22\u8d21\u732e\u8005\u3002</html>
launcher.about=<html>\u9ed8\u8ba4\u80cc\u666f\u56fe\u6765\u81eaLiberty Dome\u670d\u52a1\u5668\u3002<br/>\u5173\u4e8e\u4f5c\u8005\uff1a<br/>\n\u767e\u5ea6ID\uff1ahuanghongxun20<br/>\nmcbbs\uff1ahuanghongxun<br/>\n\u90ae\u7bb1\uff1ahuanghongxun2008@126.com<br/>\nMinecraft Forum ID: klkl6523<br/>\n\u6b22\u8fce\u63d0\u4ea4Bug\u54e6<br/>\nCopyright (c) 2013-2015 huangyuhui.<br/>\u514d\u8d23\u58f0\u660e\uff1aMinecraft\u8f6f\u4ef6\u7248\u6743\u5f52Mojang AB\u6240\u6709\uff0c\u6e38\u620f\u7531\u4e8e\u8bef\u64cd\u4f5c\u672c\u542f\u52a8\u5668\u800c\u4e22\u5931\u6570\u636e\u7684\u6982\u4e0d\u8d1f\u8d23\u3002<br/>\u672c\u542f\u52a8\u5668\u5728GPLv3\u534f\u8bae\u4e0b\u5f00\u6e90:https://github.com/huanghongxun/HMCL/<br/>\u672c\u8f6f\u4ef6\u4f7f\u7528\u4e86\u57fa\u4e8eApache License 2.0\u7684Gson\u9879\u76ee\uff0c\u611f\u8c22\u8d21\u732e\u8005\u3002</html>
launcher.download_source=\u4e0b\u8f7d\u6e90
launcher.background_location=\u80cc\u666f\u5730\u5740
launcher.exit_failed=\u5f3a\u5236\u9000\u51fa\u5931\u8d25\uff0c\u53ef\u80fd\u662fForge 1.7.10\u53ca\u66f4\u9ad8\u7248\u672c\u5bfc\u81f4\u7684\uff0c\u65e0\u6cd5\u89e3\u51b3\u3002