blob: 9867a4fcc8dc77d628e5c6556a9653421f5db9bc [file] [log] [blame]
/*
* 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.jackrabbit.oak.api;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import javax.jcr.PropertyType;
import org.jetbrains.annotations.NotNull;
/**
* Instances of this class map Java types to {@link PropertyType property types}.
* Passing an instance of this class to {@link PropertyState#getValue(Type)} determines
* the return type of that method.
* @param <T>
*/
public final class Type<T> implements Comparable<Type<?>> {
private static final Map<String, Type<?>> TYPES = new HashMap<String, Type<?>>();
private static <T> Type<T> create(int tag, boolean array, String string) {
Type<T> type = new Type<T>(tag, array, string);
TYPES.put(string, type);
return type;
}
/** Map {@code String} to {@link PropertyType#STRING} */
public static final Type<String> STRING =
create(PropertyType.STRING, false, "STRING");
/** Map {@code Blob} to {@link PropertyType#BINARY} */
public static final Type<Blob> BINARY =
create(PropertyType.BINARY, false, "BINARY");
/** Map {@code Long} to {@link PropertyType#LONG} */
public static final Type<Long> LONG =
create(PropertyType.LONG, false, "LONG");
/** Map {@code Double} to {@link PropertyType#DOUBLE} */
public static final Type<Double> DOUBLE =
create(PropertyType.DOUBLE, false, "DOUBLE");
/** Map {@code String} to {@link PropertyType#DATE} */
public static final Type<String> DATE =
create(PropertyType.DATE, false, "DATE");
/** Map {@code Boolean} to {@link PropertyType#BOOLEAN} */
public static final Type<Boolean> BOOLEAN =
create(PropertyType.BOOLEAN, false, "BOOLEAN");
/** Map {@code String} to {@link PropertyType#STRING} */
public static final Type<String> NAME =
create(PropertyType.NAME, false, "NAME");
/** Map {@code String} to {@link PropertyType#PATH} */
public static final Type<String> PATH =
create(PropertyType.PATH, false, "PATH");
/** Map {@code String} to {@link PropertyType#REFERENCE} */
public static final Type<String> REFERENCE =
create(PropertyType.REFERENCE, false, "REFERENCE");
/** Map {@code String} to {@link PropertyType#WEAKREFERENCE} */
public static final Type<String> WEAKREFERENCE =
create(PropertyType.WEAKREFERENCE, false, "WEAKREFERENCE");
/** Map {@code String} to {@link PropertyType#URI} */
public static final Type<String> URI =
create(PropertyType.URI, false, "URI");
/** Map {@code BigDecimal} to {@link PropertyType#DECIMAL} */
public static final Type<BigDecimal> DECIMAL =
create(PropertyType.DECIMAL, false, "DECIMAL");
/** Map {@code Iterable<String>} to array of {@link PropertyType#STRING} */
public static final Type<Iterable<String>> STRINGS =
create(PropertyType.STRING, true, "STRINGS");
/** Map {@code Iterable<Blob>} to array of {@link PropertyType#BINARY} */
public static final Type<Iterable<Blob>> BINARIES =
create(PropertyType.BINARY, true, "BINARIES");
/** Map {@code Iterable<Long>} to array of {@link PropertyType#LONG} */
public static final Type<Iterable<Long>> LONGS =
create(PropertyType.LONG, true, "LONGS");
/** Map {@code Iterable<Double>} to array of {@link PropertyType#DOUBLE} */
public static final Type<Iterable<Double>> DOUBLES =
create(PropertyType.DOUBLE, true, "DOUBLES");
/** Map {@code Iterable<String>} to array of {@link PropertyType#DATE} */
public static final Type<Iterable<String>> DATES =
create(PropertyType.DATE, true, "DATES");
/** Map {@code Iterable<Boolean>} to array of {@link PropertyType#BOOLEAN} */
public static final Type<Iterable<Boolean>> BOOLEANS =
create(PropertyType.BOOLEAN, true, "BOOLEANS");
/** Map {@code Iterable<String>} to array of {@link PropertyType#NAME} */
public static final Type<Iterable<String>> NAMES =
create(PropertyType.NAME, true, "NAMES");
/** Map {@code Iterable<String>} to array of {@link PropertyType#PATH} */
public static final Type<Iterable<String>> PATHS =
create(PropertyType.PATH, true, "PATHS");
/** Map {@code Iterable<String>} to array of {@link PropertyType#REFERENCE} */
public static final Type<Iterable<String>> REFERENCES =
create(PropertyType.REFERENCE, true, "REFERENCES");
/** Map {@code Iterable<String>} to array of {@link PropertyType#WEAKREFERENCE} */
public static final Type<Iterable<String>> WEAKREFERENCES =
create(PropertyType.WEAKREFERENCE, true, "WEAKREFERENCES");
/** Map {@code Iterable<String>} to array of {@link PropertyType#URI} */
public static final Type<Iterable<String>> URIS =
create(PropertyType.URI, true, "URIS");
/** Map {@code Iterable<BigDecimal>} to array of {@link PropertyType#DECIMAL} */
public static final Type<Iterable<BigDecimal>> DECIMALS =
create(PropertyType.DECIMAL, true, "DECIMALS");
/** The special "undefined" type, never encountered in normal values */
public static final Type<Void> UNDEFINED =
create(PropertyType.UNDEFINED, false, "UNDEFINED");
/** Multi-valued "undefined" type, never encountered in normal values */
public static final Type<Iterable<Void>> UNDEFINEDS =
create(PropertyType.UNDEFINED, true, "UNDEFINEDS");
private final int tag;
private final boolean array;
private final String string;
private Type(int tag, boolean array, String string) {
this.tag = tag;
this.array = array;
this.string = string;
}
/**
* Corresponding type tag as defined in {@link PropertyType}.
* @return type tag
*/
public int tag() {
return tag;
}
/**
* Determine whether this is an array type
* @return {@code true} if and only if this is an array type
*/
public boolean isArray() {
return array;
}
/**
* Corresponding {@code Type} for a given type tag and array flag.
* @param tag type tag as defined in {@link PropertyType}.
* @param array whether this is an array or not
* @return {@code Type} instance
* @throws IllegalArgumentException if tag is not valid as per definition in {@link PropertyType}.
*/
public static Type<?> fromTag(int tag, boolean array) {
switch (tag) {
case PropertyType.STRING: return array ? STRINGS : STRING;
case PropertyType.BINARY: return array ? BINARIES : BINARY;
case PropertyType.LONG: return array ? LONGS : LONG;
case PropertyType.DOUBLE: return array ? DOUBLES : DOUBLE;
case PropertyType.DATE: return array ? DATES: DATE;
case PropertyType.BOOLEAN: return array ? BOOLEANS: BOOLEAN;
case PropertyType.NAME: return array ? NAMES : NAME;
case PropertyType.PATH: return array ? PATHS: PATH;
case PropertyType.REFERENCE: return array ? REFERENCES : REFERENCE;
case PropertyType.WEAKREFERENCE: return array ? WEAKREFERENCES : WEAKREFERENCE;
case PropertyType.URI: return array ? URIS: URI;
case PropertyType.DECIMAL: return array ? DECIMALS : DECIMAL;
case PropertyType.UNDEFINED: return array ? UNDEFINEDS : UNDEFINED;
default: throw new IllegalArgumentException("Invalid type tag: " + tag);
}
}
/**
* Returns the {@code Type} with the given string representation.
*
* @param string type string
* @return matching type
*/
public static Type<?> fromString(String string) {
Type<?> type = TYPES.get(string);
if (type == null) {
throw new IllegalArgumentException("Invalid type name: " + string);
}
return type;
}
/**
* Determine the base type of array types
* @return base type
* @throws IllegalStateException if {@code isArray} is false.
*/
public Type<?> getBaseType() {
checkState(isArray(), "Not an array");
return fromTag(tag, false);
}
/**
* Determine the array type which has this type as base type
* @return array type with this type as base type
* @throws IllegalStateException if {@code isArray} is true.
*/
public Type<?> getArrayType() {
checkState(!isArray(), "Not a simply type");
return fromTag(tag, true);
}
//--------------------------------------------------------< Comparable >--
@Override
public int compareTo(@NotNull Type<?> that) {
if (tag < that.tag) {
return -1;
}
if (tag > that.tag) {
return 1;
}
if (!array && that.array) {
return -1;
}
if (array && !that.array) {
return 1;
}
return 0;
}
//------------------------------------------------------------< Object >--
@Override
public String toString() {
return string;
}
@Override
public int hashCode() {
int result = 1;
result = result + 31 * tag;
result = result + 31 * hashCode(array);
return result;
}
private int hashCode(boolean value) {
return value ? 1231 : 1237;
}
private void checkState(boolean condition, String message) {
if (!condition) {
throw new IllegalStateException(message);
}
}
@Override
public boolean equals(Object other) {
return this == other;
}
}