/* * ModeShape (http://www.modeshape.org) * * 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 org.modeshape.jcr.query.model; import java.io.Serializable; import java.math.BigDecimal; import java.util.Comparator; import java.util.Set; import org.modeshape.common.annotation.Immutable; import org.modeshape.jcr.cache.NodeKey; import org.modeshape.jcr.value.BinaryValue; import org.modeshape.jcr.value.Name; import org.modeshape.jcr.value.Path; import org.modeshape.jcr.value.Reference; import org.modeshape.jcr.value.ValueFormatException; /** * An interface that defines the value types used in tuples. */ @Immutable public abstract class TypeSystem { /** * Get the type factory given the name of the type. * * @param typeName the name of the type * @return the type factory, or null if there is no such type in this system */ public abstract TypeFactory<?> getTypeFactory( String typeName ); /** * Get the type factory for the type denoted by the supplied prototype value. * * @param prototype the value whose type is to be identified * @return the type factory, or null if there is no such type in this system */ public abstract TypeFactory<?> getTypeFactory( Object prototype ); /** * Get the type factory for boolean types. * * @return the boolean factory; never null */ public abstract TypeFactory<Boolean> getBooleanFactory(); /** * Get the type factory for long types. * * @return the long factory; never null */ public abstract TypeFactory<Long> getLongFactory(); /** * Get the type factory for string types. * * @return the string factory; never null */ public abstract TypeFactory<String> getStringFactory(); /** * Get the type factory for double types. * * @return the double factory; never null */ public abstract TypeFactory<Double> getDoubleFactory(); /** * Get the type factory for decimal types. * * @return the decimal factory; never null */ public abstract TypeFactory<BigDecimal> getDecimalFactory(); /** * Get the type factory for date-time objects. * * @return the date-time factory, or null if this type system doesn't support date-time objects */ public abstract TypeFactory<?> getDateTimeFactory(); /** * Get the type factory for path objects. * * @return the path factory, or null if this type system doesn't support path objects */ public abstract TypeFactory<Path> getPathFactory(); /** * Get the type factory for name objects. * * @return the name factory, or null if this type system doesn't support path objects */ public abstract TypeFactory<Name> getNameFactory(); /** * Get the type factory for references objects. * * @return the reference factory, or null if this type system doesn't support reference objects */ public abstract TypeFactory<Reference> getReferenceFactory(); /** * Get the type factory for node key objects. * * @return the node key factory, or null if this type system doesn't support node key objects */ public abstract TypeFactory<NodeKey> getNodeKeyFactory(); /** * Get the type factory for binary objects. * * @return the binary factory, or null if this type system doesn't support binary objects */ public abstract TypeFactory<BinaryValue> getBinaryFactory(); /** * Get the name of the type that is used by default. * * @return the default type name; never null */ public abstract String getDefaultType(); /** * Get the comparator that should be used by default. * * @return the default comparator; never null */ public abstract Comparator<Object> getDefaultComparator(); /** * Get the names of the supported types. * * @return the immutable set of the uppercase names of the types; never null */ public abstract Set<String> getTypeNames(); /** * Get the string representation of the supplied value, using the most appropriate factory given the value. * * @param value the value * @return the string representation; never null */ public abstract String asString( Object value ); /** * Get the type that is compatible with both of the supplied types. * * @param type1 the first type; may be null * @param type2 the second type; may be null * @return the compatible type; never null */ public abstract String getCompatibleType( String type1, String type2 ); /** * Get the type that is compatible with both of the supplied types. * * @param type1 the first type; may be null * @param type2 the second type; may be null * @return the compatible type; never null */ public abstract TypeFactory<?> getCompatibleType( TypeFactory<?> type1, TypeFactory<?> type2 ); /** * Factory interface for creating values from strings. * * @param <T> the type of value object */ public static interface TypeFactory<T> { /** * Get the class representing the value type. * * @return the value type; never null */ Class<T> getType(); /** * Get a comparator that can be used to store the values of this type. * * @return the comparator; never null */ Comparator<T> getComparator(); /** * Get the name of the type created by this factory. * * @return the type name; never null and never empty or blank */ String getTypeName(); /** * Create the typed representation of the value given the supplied string representation. * * @param value the string representation of the value * @return the typed representation, which will be an instance of the {@link #getType() type} * @throws ValueFormatException if the string cannot be converted to a typed value */ T create( String value ) throws ValueFormatException; /** * Create the typed representation of the value given the supplied object representation. * * @param value the object representation of the value * @return the typed representation, which will be an instance of the {@link #getType() type} * @throws ValueFormatException if the object cannot be converted to a typed value */ T create( Object value ) throws ValueFormatException; /** * Get the string representation of the supplied value. * * @param value the value * @return the string representation; never null */ String asString( Object value ); /** * Get the length of the supplied value. * * @param value the value * @return the length; never negative */ long length( Object value ); /** * Get a readable and potentially shorter string representation of the supplied value. * * @param value the value * @return the readable string representation; never null */ String asReadableString( Object value ); } public static interface SerializableComparator<T> extends Comparator<T>, Serializable { } /** * Return a new type factory that has a comparator that inverts the normal comparison. * * @param original the original type factory; may not be null * @param comparator the new comparator to use; may be null * @return the new type factory; never null, but {@code original} if {@code comparator} is null */ public static <T> TypeFactory<T> withComparator( final TypeFactory<T> original, final Comparator<T> comparator ) { if (comparator == null) return original; return new TypeFactory<T>() { @Override public Class<T> getType() { return original.getType(); } @Override public Comparator<T> getComparator() { return comparator; } @Override public String getTypeName() { return original.getTypeName(); } @Override public T create( String value ) throws ValueFormatException { return original.create(value); } @Override public T create( Object value ) throws ValueFormatException { return original.create(value); } @Override public String asString( Object value ) { return original.asString(value); } @Override public long length( Object value ) { return original.length(value); } @Override public String asReadableString( Object value ) { return original.asReadableString(value); } @Override public String toString() { return original.toString() + " with comparator " + comparator; } }; } /** * Return a new type factory that has a comparator that inverts the normal comparison. * * @param original the original type factory; may not be null * @return the new type factory; never null */ public static <T> TypeFactory<T> withOppositeComparator( final TypeFactory<T> original ) { final Comparator<T> comparator = original.getComparator(); final Comparator<T> inverted = new SerializableComparator<T>() { private static final long serialVersionUID = 1L; @Override public int compare( T arg0, T arg1 ) { return comparator.compare(arg1, arg0); } }; return withComparator(original, inverted); } /** * Return a new type factory that has a comparator that uses the supplied {@link Order} and {@link NullOrder} behavior. * * @param original the original type factory; may not be null * @param order the specification of whether the comparator should order ascending or descending; may not be null * @param nullOrder the specification of whether null values should appear first or last; may not be null * @return the new type factory; never null, but possibly {@code original} if it has the desired behavior */ public static <T> TypeFactory<T> with( final TypeFactory<T> original, final Order order, final NullOrder nullOrder ) { final Comparator<T> comparator = original.getComparator(); final String toString = "Comparator<" + original.getTypeName() + ">(" + order + " " + nullOrder + ")"; switch (order) { case ASCENDING: switch (nullOrder) { case NULLS_FIRST: // Nulls must be first, so we can just check that before we delegate to the original comparator ... Comparator<T> nullFirst = new SerializableComparator<T>() { private static final long serialVersionUID = 1L; @Override public int compare( T o1, T o2 ) { if (o1 == null) return -1; if (o2 == null) return 1; assert o1 != null; assert o2 != null; return comparator.compare(o1, o2); // order is same! } @Override public String toString() { return toString; } }; return withComparator(original, nullFirst); case NULLS_LAST: // Otherwise, nulls must be last, so we can just check that before we delegate to the original comparator // ... Comparator<T> nullLast = new SerializableComparator<T>() { private static final long serialVersionUID = 1L; @Override public int compare( T o1, T o2 ) { if (o1 == null) return 1; if (o2 == null) return -1; assert o1 != null; assert o2 != null; return comparator.compare(o1, o2); // order is same! } @Override public String toString() { return toString; } }; return withComparator(original, nullLast); } assert false; break; case DESCENDING: switch (nullOrder) { case NULLS_FIRST: // Otherwise, nulls must be last, so we can just check that before we delegate to the original comparator // ... Comparator<T> nullFirst = new SerializableComparator<T>() { private static final long serialVersionUID = 1L; @Override public int compare( T o1, T o2 ) { if (o1 == null) return -1; if (o2 == null) return 1; assert o1 != null; assert o2 != null; return comparator.compare(o2, o1); // order is different! } @Override public String toString() { return toString; } }; return withComparator(original, nullFirst); case NULLS_LAST: // Otherwise, nulls must be last, so we can just check that before we delegate to the original comparator // ... Comparator<T> nullLast = new SerializableComparator<T>() { private static final long serialVersionUID = 1L; @Override public int compare( T o1, T o2 ) { if (o1 == null) return 1; if (o2 == null) return -1; assert o1 != null; assert o2 != null; return comparator.compare(o2, o1); // order is different! } @Override public String toString() { return toString; } }; return withComparator(original, nullLast); } } assert false; return null; } }