org.opencastproject.assetmanager.api.Value Maven / Gradle / Ivy
/*
* Licensed to The Apereo Foundation under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
*
* The Apereo Foundation licenses this file to you under the Educational
* Community 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://opensource.org/licenses/ecl2.txt
*
* 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.opencastproject.assetmanager.api;
import static java.lang.String.format;
import org.opencastproject.assetmanager.api.fn.Product;
import java.util.Date;
import java.util.Objects;
import java.util.function.Function;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* A property value.
*
* The wrapped type is not exposed as a generic type parameter since {@link Value}s appear in
* contexts like lists where this type information cannot be preserved.
* To access the wrapped type one can choose between two options.
* If the type is known, use {@link #get(ValueType)}.
* If the type is not known, safely decompose the value with {@link #decompose(Fn, Fn, Fn, Fn, Fn)}.
*
* The value type is a sum type made up from
*
* - {@link StringValue}
*
- {@link DateValue}
*
- {@link LongValue}
*
- {@link BooleanValue}
*
*
* Use one of the various mk(..)
constructors to create a new {@link Value}.
*
* @see Property
*/
@ParametersAreNonnullByDefault
public abstract class Value {
public static final StringType STRING = new StringType();
public static final DateType DATE = new DateType();
public static final LongType LONG = new LongType();
public static final BooleanType BOOLEAN = new BooleanType();
public static final VersionType VERSION = new VersionType();
// TODO: rename to UNKNOWN
public static final UntypedType UNTYPED = new UntypedType();
// public static final Class UNTYPED = UntypedValue.class;
private Value() {
}
/** Get the wrapped value. */
public abstract Object get();
/**
* Get the wrapped value in a type safe way. Use this method if you are
* sure about the contained value type. Otherwise consider the use
* of {@link #decompose(Fn, Fn, Fn, Fn, Fn)}.
*
* @param ev
* Evidence type. The type parameter A
of the evidence type
* must match the type of the wrapped value. Any other value will result
* in an exception being thrown.
* @throws java.lang.RuntimeException
* if the passed evidence ev
does not match the type of the wrapped value
*/
public final A get(ValueType ev) {
if (getType().getClass().equals(ev.getClass())) {
return (A) get();
} else {
throw new RuntimeException(this + " is not a " + ev.getClass().getSimpleName());
}
}
public final ValueType> getType() {
return decompose(new Function>() {
@Override public ValueType> apply(String a) {
return STRING;
}
}, new Function>() {
@Override public ValueType> apply(Date a) {
return DATE;
}
}, new Function>() {
@Override public ValueType> apply(Long a) {
return LONG;
}
}, new Function>() {
@Override public ValueType> apply(Boolean a) {
return BOOLEAN;
}
}, new Function>() {
@Override public ValueType> apply(Version a) {
return VERSION;
}
});
}
/**
* Decompose (or pattern match) the value instance. Provide a function to handle each possible type.
* Use {@link #doNotMatch()} as a placeholder that yields an error.
*/
public final A decompose(
Function super String, ? extends A> stringValue,
Function super Date, ? extends A> dateValue,
Function super Long, ? extends A> longValue,
Function super Boolean, ? extends A> booleanValue,
Function super Version, ? extends A> versionValue
) {
if (this instanceof StringValue) {
return stringValue.apply(((StringValue) this).get());
} else if (this instanceof DateValue) {
return dateValue.apply(((DateValue) this).get());
} else if (this instanceof LongValue) {
return longValue.apply(((LongValue) this).get());
} else if (this instanceof BooleanValue) {
return booleanValue.apply(((BooleanValue) this).get());
} else if (this instanceof VersionValue) {
return versionValue.apply(((VersionValue) this).get());
} else {
// catch bug
throw new Error("Unexhaustive match: " + this);
}
}
//
/**
* Use as a placeholder that yields an error in
* value decomposition.
*
* @see #decompose(Fn, Fn, Fn, Fn, Fn)
*/
public static Function