Change the license to GPL v3 to be compatible with Apache License 2.0.

This commit is contained in:
huanghongxun
2015-12-05 21:41:50 +08:00
parent f0212ea4eb
commit d3ad805ad3
331 changed files with 12761 additions and 1878 deletions

View File

@@ -0,0 +1,74 @@
/**
* 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 AtomicReference<Subscription> actualSubscription = new AtomicReference<Subscription>();
private 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

@@ -0,0 +1,97 @@
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

@@ -0,0 +1,65 @@
/**
* 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<Exception>();
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

@@ -0,0 +1,31 @@
/**
* 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

@@ -0,0 +1,75 @@
/**
* 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

@@ -0,0 +1,108 @@
/**
* 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

@@ -0,0 +1,20 @@
/**
* 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

@@ -0,0 +1,20 @@
/**
* 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

@@ -0,0 +1,20 @@
/**
* 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

@@ -0,0 +1,20 @@
/**
* 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

@@ -0,0 +1,20 @@
/**
* 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

@@ -0,0 +1,20 @@
/**
* 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

@@ -0,0 +1,20 @@
/**
* 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

@@ -0,0 +1,20 @@
/**
* 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

@@ -0,0 +1,20 @@
/**
* 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

@@ -0,0 +1,20 @@
/**
* 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

@@ -0,0 +1,20 @@
/**
* 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

@@ -0,0 +1,20 @@
/**
* 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

@@ -0,0 +1,20 @@
/**
* 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

@@ -0,0 +1,20 @@
/**
* 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

@@ -0,0 +1,20 @@
/**
* 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

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

View File

@@ -0,0 +1,39 @@
/**
* 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

@@ -0,0 +1,579 @@
/**
* 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;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
import org.jackhuang.hellominecraft.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<Class<?>, FunctionLanguageAdaptor>();
static {
/* optimistically look for supported languages if they are in the classpath */
loadLanguageAdaptor("Groovy");
loadLanguageAdaptor("JRuby");
loadLanguageAdaptor("Clojure");
loadLanguageAdaptor("Scala");
// as new languages arise we can add them here but this does not prevent someone from using 'registerLanguageAdaptor' directly
}
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 new FuncN<R>() {
@Override
public R call(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 new FuncN<R>() {
@SuppressWarnings("unchecked")
@Override
public R call(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 new FuncN<R>() {
@SuppressWarnings("unchecked")
@Override
public R call(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 new FuncN<R>() {
@SuppressWarnings("unchecked")
@Override
public R call(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 new FuncN<R>() {
@SuppressWarnings("unchecked")
@Override
public R call(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 new FuncN<R>() {
@SuppressWarnings("unchecked")
@Override
public R call(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 new FuncN<R>() {
@SuppressWarnings("unchecked")
@Override
public R call(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 new FuncN<R>() {
@SuppressWarnings("unchecked")
@Override
public R call(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 new FuncN<R>() {
@SuppressWarnings("unchecked")
@Override
public R call(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 new FuncN<R>() {
@SuppressWarnings("unchecked")
@Override
public R call(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 new FuncN<Void>() {
@Override
public Void call(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 new FuncN<Void>() {
@SuppressWarnings("unchecked")
@Override
public Void call(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 new FuncN<Void>() {
@SuppressWarnings("unchecked")
@Override
public Void call(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 new FuncN<Void>() {
@SuppressWarnings("unchecked")
@Override
public Void call(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;
}
}
}