
org.apache.brooklyn.util.guava.Maybe Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of brooklyn-utils-common Show documentation
Show all versions of brooklyn-utils-common Show documentation
Utility classes and methods developed for Brooklyn but not dependendent on Brooklyn or much else
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.brooklyn.util.guava;
import static com.google.common.base.Preconditions.checkNotNull;
import java.io.Serializable;
import java.lang.ref.SoftReference;
import java.util.Collections;
import java.util.Iterator;
import java.util.Set;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.apache.brooklyn.util.javalang.JavaClassNames;
import com.google.common.annotations.Beta;
import com.google.common.base.Function;
import com.google.common.base.Objects;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Supplier;
import com.google.common.collect.AbstractIterator;
import com.google.common.collect.ImmutableSet;
/** Like Guava Optional but permitting null and permitting errors to be thrown. */
public abstract class Maybe implements Serializable, Supplier {
private static final long serialVersionUID = -6372099069863179019L;
public static Maybe absent() {
return new Absent();
}
/** Creates an absent whose get throws an {@link IllegalStateException} with the indicated message.
* Both stack traces (the cause and the callers) are provided, which can be quite handy. */
public static Maybe absent(final String message) {
return absent(new IllegalStateExceptionSupplier(message));
}
/** Creates an absent whose get throws an {@link IllegalStateException} with the indicated cause.
* Both stack traces (the cause and the callers) are provided, which can be quite handy. */
public static Maybe absent(final Throwable cause) {
return absent(new IllegalStateExceptionSupplier(cause));
}
/** Creates an absent whose get throws an {@link IllegalStateException} with the indicated message and underlying cause.
* Both stack traces (the cause and the callers) are provided, which can be quite handy. */
public static Maybe absent(final String message, final Throwable cause) {
return absent(new IllegalStateExceptionSupplier(message, cause));
}
/** Creates an absent whose get throws an {@link RuntimeException} generated on demand from the given supplier */
public static Maybe absent(final Supplier extends RuntimeException> exceptionSupplier) {
return new Absent(Preconditions.checkNotNull(exceptionSupplier));
}
/** as {@link #absentNull(String)} but with a generic message */
public static Maybe absentNull() {
return absentNull("value is null");
}
/** like {@link #absent(String)} but {@link #isNull()} will return true on the result. */
public static Maybe absentNull(String message) {
return new AbsentNull(message);
}
/** Creates a new Maybe object which is present.
* The argument may be null and the object still present,
* which may be confusing in some contexts
* (traditional {@link Optional} usages) but
* may be natural in others (where null is a valid value, distinguished from no value set).
* See also {@link #ofDisallowingNull(Object)}. */
public static Maybe ofAllowingNull(@Nullable T value) {
return new Present(value);
}
/** Creates a new Maybe object which is present if and only if the argument is not null.
* If the argument is null, then an {@link #absentNull()} is returned,
* on which {@link #isNull()} will be true. */
public static Maybe ofDisallowingNull(@Nullable T value) {
if (value==null) return absentNull();
return new Present(value);
}
/** Creates a new Maybe object.
* Currently this uses {@link #ofAllowingNull(Object)} semantics,
* but it is recommended to use that method for clarity
* if the argument might be null. */
// note: Optional throws if null is supplied; we might want to do the same here
public static Maybe of(@Nullable T value) {
return ofAllowingNull(value);
}
/** Creates a new Maybe object using {@link #ofDisallowingNull(Object)} semantics.
* It is recommended to use that method for clarity.
* This method is provided for consistency with {@link Optional#fromNullable(Object)}. */
public static Maybe fromNullable(@Nullable T value) {
return ofDisallowingNull(value);
}
/** creates an instance wrapping a {@link SoftReference}, so it might go absent later on.
* if null is supplied the result is a present null. */
public static Maybe soft(@Nonnull T value) {
return softThen(value, null);
}
/** creates an instance wrapping a {@link SoftReference}, using the second item given
* if the first argument is dereferenced.
* however if the first argument is null, this is a permanent present null,
* as {@link #of(Object)} with null. */
public static Maybe softThen(T value, Maybe ifEmpty) {
if (value==null) return of((T)null);
return new SoftlyPresent(value).usingAfterExpiry(ifEmpty);
}
public static Maybe of(final Optional value) {
if (value.isPresent()) return new AbstractPresent() {
private static final long serialVersionUID = -5735268814211401356L;
@Override
public T get() {
return value.get();
}
@Override
public boolean isNull() {
// should always be false as per Optional contract
return get()==null;
}
};
return absent();
}
public static Maybe of(final Supplier value) {
return new AbstractPresent() {
private static final long serialVersionUID = -5735268814211401356L;
@Override
public T get() {
return value.get();
}
@Override
public boolean isNull() {
return get()==null;
}
};
}
/** returns a Maybe containing the next element in the iterator, or absent if none */
public static Maybe next(Iterator iterator) {
return iterator.hasNext() ? Maybe.of(iterator.next()) : Maybe.absent();
}
public abstract boolean isPresent();
public abstract T get();
public boolean isAbsent() {
return !isPresent();
}
public boolean isAbsentOrNull() {
return isAbsent() || isNull();
}
public boolean isPresentAndNonNull() {
return isPresent() && !isNull();
}
/** Whether the value is null, if present, or
* if it was specified as absent because it was null,
* e.g. using {@link #fromNullable(Object)}.
*/
public abstract boolean isNull();
public T or(T nextValue) {
if (isPresent()) return get();
return nextValue;
}
public Maybe or(Maybe nextValue) {
if (isPresent()) return this;
return nextValue;
}
public T or(Supplier nextValue) {
if (isPresent()) return get();
return nextValue.get();
}
public T orNull() {
if (isPresent()) return get();
return null;
}
public Set asSet() {
if (isPresent()) return ImmutableSet.of(get());
return Collections.emptySet();
}
public Maybe transform(final Function super T, V> f) {
if (isPresent()) return new AbstractPresent() {
private static final long serialVersionUID = 325089324325L;
public V get() {
return f.apply(Maybe.this.get());
}
@Override
public boolean isNull() {
return get()==null;
}
};
return absent();
}
/**
* Returns the value of each present instance from the supplied {@code maybes}, in order,
* skipping over occurrences of {@link Maybe#absent()}. Iterators are unmodifiable and are
* evaluated lazily.
*
* @see Optional#presentInstances(Iterable)
*/
@Beta
public static Iterable presentInstances(final Iterable extends Maybe extends T>> maybes) {
checkNotNull(maybes);
return new Iterable() {
@Override
public Iterator iterator() {
return new AbstractIterator() {
private final Iterator extends Maybe extends T>> iterator = checkNotNull(maybes.iterator());
@Override
protected T computeNext() {
while (iterator.hasNext()) {
Maybe extends T> maybe = iterator.next();
if (maybe.isPresent()) { return maybe.get(); }
}
return endOfData();
}
};
}
};
}
public static class Absent extends Maybe {
private static final long serialVersionUID = -757170462010887057L;
private final Supplier extends RuntimeException> exception;
public Absent() {
this(IllegalStateExceptionSupplier.EMPTY_EXCEPTION);
}
public Absent(Supplier extends RuntimeException> exception) {
this.exception = exception;
}
@Override
public boolean isPresent() {
return false;
}
@Override
public boolean isNull() {
return false;
}
@Override
public T get() {
throw getException();
}
public RuntimeException getException() {
return exception.get();
}
}
public static class AbsentNull extends Absent {
private static final long serialVersionUID = 2422627709567857268L;
public AbsentNull(String message) {
super(new IllegalStateExceptionSupplier(message));
}
@Override
public boolean isNull() {
return true;
}
}
public static abstract class AbstractPresent extends Maybe {
private static final long serialVersionUID = -2266743425340870492L;
protected AbstractPresent() {
}
@Override
public boolean isPresent() {
return true;
}
}
public static class Present extends AbstractPresent {
private static final long serialVersionUID = 436799990500336015L;
private final T value;
protected Present(T value) {
this.value = value;
}
@Override
public T get() {
return value;
}
@Override
public boolean isNull() {
return value==null;
}
}
public static class SoftlyPresent extends Maybe {
private static final long serialVersionUID = 436799990500336015L;
private final SoftReference value;
private Maybe defaultValue;
protected SoftlyPresent(@Nonnull T value) {
this.value = new SoftReference(value);
}
@Override
public T get() {
T result = value.get();
if (result!=null) return result;
if (defaultValue==null) throw new IllegalStateException("Softly present item has been GC'd");
return defaultValue.get();
}
@Override
public T orNull() {
T result = value.get();
if (result!=null) return result;
if (defaultValue==null) return null;
return defaultValue.orNull();
}
@Override
public boolean isPresent() {
return value.get()!=null || (defaultValue!=null && defaultValue.isPresent());
}
@Override
public boolean isNull() {
// null not allowed here
return false;
}
public Maybe solidify() {
return Maybe.fromNullable(value.get());
}
SoftlyPresent usingAfterExpiry(Maybe defaultValue) {
this.defaultValue = defaultValue;
return this;
}
}
@Override
public String toString() {
return JavaClassNames.simpleClassName(this)+"["+(isPresent()?"value="+get():"")+"]";
}
@Override
public int hashCode() {
if (!isPresent()) return Objects.hashCode(31, isPresent());
return Objects.hashCode(31, get());
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Maybe)) return false;
Maybe> other = (Maybe>)obj;
if (!isPresent())
return !other.isPresent();
return Objects.equal(get(), other.get());
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy