Search in sources :

Example 1 with CoercionTuple

use of org.apache.tapestry5.commons.services.CoercionTuple in project tapestry-5 by apache.

the class TypeCoercerImpl method queueIntermediates.

/**
 * Creates and adds to the pool a new set of coercions based on an intermediate tuple. Adds
 * compound coercion tuples
 * to the end of the queue.
 *
 * @param sourceType
 *         the source type of the coercion
 * @param targetType
 *         TODO
 * @param intermediateTuple
 *         a tuple that converts from the source type to some intermediate type (that is not
 *         assignable to the target type)
 * @param consideredTuples
 *         set of tuples that have already been added to the pool (directly, or as a compound
 *         coercion)
 * @param queue
 *         the work queue of tuples
 */
@SuppressWarnings("unchecked")
private void queueIntermediates(Class sourceType, Class targetType, CoercionTuple intermediateTuple, Set<CoercionTuple.Key> consideredTuples, LinkedList<CoercionTuple> queue) {
    Class intermediateType = intermediateTuple.getTargetType();
    for (Class c : new InheritanceSearch(intermediateType)) {
        for (CoercionTuple tuple : getTuples(c, targetType)) {
            if (consideredTuples.contains(tuple.getKey())) {
                continue;
            }
            Class newIntermediateType = tuple.getTargetType();
            if (sourceType.isAssignableFrom(newIntermediateType)) {
                continue;
            }
            // The intermediateTuple coercer gets from S --> I1 (an intermediate type).
            // The current tuple's coercer gets us from I2 --> X. where I2 is assignable
            // from I1 (i.e., I2 is a superclass/superinterface of I1) and X is a new
            // intermediate type, hopefully closer to our eventual target type.
            Coercion compoundCoercer = new CompoundCoercion(intermediateTuple.getCoercion(), tuple.getCoercion());
            CoercionTuple compoundTuple = new CoercionTuple(sourceType, newIntermediateType, compoundCoercer, false);
            // So, every tuple that is added to the queue can take as input the sourceType.
            // The target type may be another intermediate type, or may be something
            // assignable to the target type, which will bring the search to a successful
            // conclusion.
            queue.addLast(compoundTuple);
            consideredTuples.add(tuple.getKey());
        }
    }
}
Also used : CoercionTuple(org.apache.tapestry5.commons.services.CoercionTuple) InheritanceSearch(org.apache.tapestry5.commons.internal.util.InheritanceSearch) StringToEnumCoercion(org.apache.tapestry5.commons.util.StringToEnumCoercion) Coercion(org.apache.tapestry5.commons.services.Coercion)

Example 2 with CoercionTuple

use of org.apache.tapestry5.commons.services.CoercionTuple in project tapestry-5 by apache.

the class TypeCoercerImpl method findOrCreateCoercion.

/**
 * Here's the real meat; we do a search of the space to find coercions, or a system of
 * coercions, that accomplish
 * the desired coercion.
 *
 * There's <strong>TREMENDOUS</strong> room to improve this algorithm. For example, inheritance lists could be
 * cached. Further, there's probably more ways to early prune the search. However, even with dozens or perhaps
 * hundreds of tuples, I suspect the search will still grind to a conclusion quickly.
 *
 * The order of operations should help ensure that the most efficient tuple chain is located. If you think about how
 * tuples are added to the queue, there are two factors: size (the number of steps in the coercion) and
 * "class distance" (that is, number of steps up the inheritance hiearchy). All the appropriate 1 step coercions
 * will be considered first, in class distance order. Along the way, we'll queue up all the 2 step coercions, again
 * in class distance order. By the time we reach some of those, we'll have begun queueing up the 3 step coercions, and
 * so forth, until we run out of input tuples we can use to fabricate multi-step compound coercions, or reach a
 * final response.
 *
 * This does create a good number of short lived temporary objects (the compound tuples), but that's what the GC is
 * really good at.
 *
 * @param sourceType
 * @param targetType
 * @return coercer from sourceType to targetType
 */
@SuppressWarnings("unchecked")
private Coercion findOrCreateCoercion(Class sourceType, Class targetType) {
    if (sourceType == Void.class) {
        return searchForNullCoercion(targetType);
    }
    // Trying to find exact match.
    Optional<CoercionTuple> maybeTuple = getTuples(sourceType, targetType).stream().filter((t) -> sourceType.equals(t.getSourceType()) && targetType.equals(t.getTargetType())).findFirst();
    if (maybeTuple.isPresent()) {
        return maybeTuple.get().getCoercion();
    }
    // These are instance variables because this method may be called concurrently.
    // On a true race, we may go to the work of seeking out and/or fabricating
    // a tuple twice, but it's more likely that different threads are looking
    // for different source/target coercions.
    Set<CoercionTuple.Key> consideredTuples = CollectionFactory.newSet();
    LinkedList<CoercionTuple> queue = CollectionFactory.newLinkedList();
    seedQueue(sourceType, targetType, consideredTuples, queue);
    while (!queue.isEmpty()) {
        CoercionTuple tuple = queue.removeFirst();
        // If the tuple results in a value type that is assignable to the desired target type,
        // we're done! Later, we may add a concept of "cost" (i.e. number of steps) or
        // "quality" (how close is the tuple target type to the desired target type). Cost
        // is currently implicit, as compound tuples are stored deeper in the queue,
        // so simpler coercions will be located earlier.
        Class tupleTargetType = tuple.getTargetType();
        if (targetType.isAssignableFrom(tupleTargetType)) {
            return tuple.getCoercion();
        }
        // So .. this tuple doesn't get us directly to the target type.
        // However, it *may* get us part of the way. Each of these
        // represents a coercion from the source type to an intermediate type.
        // Now we're going to look for conversions from the intermediate type
        // to some other type.
        queueIntermediates(sourceType, targetType, tuple, consideredTuples, queue);
    }
    throw new CoercionNotFoundException(String.format("Could not find a coercion from type %s to type %s.", sourceType.getName(), targetType.getName()), buildCoercionCatalog(), sourceType, targetType);
}
Also used : PlasticUtils(org.apache.tapestry5.plastic.PlasticUtils) TypeCoercer(org.apache.tapestry5.commons.services.TypeCoercer) InternalCommonsUtils(org.apache.tapestry5.commons.internal.util.InternalCommonsUtils) Collection(java.util.Collection) Set(java.util.Set) StringToEnumCoercion(org.apache.tapestry5.commons.util.StringToEnumCoercion) LockSupport(org.apache.tapestry5.commons.internal.util.LockSupport) List(java.util.List) F(org.apache.tapestry5.func.F) Coercion(org.apache.tapestry5.commons.services.Coercion) CoercionNotFoundException(org.apache.tapestry5.commons.util.CoercionNotFoundException) CollectionFactory(org.apache.tapestry5.commons.util.CollectionFactory) Map(java.util.Map) CoercionTuple(org.apache.tapestry5.commons.services.CoercionTuple) AvailableValues(org.apache.tapestry5.commons.util.AvailableValues) Optional(java.util.Optional) InheritanceSearch(org.apache.tapestry5.commons.internal.util.InheritanceSearch) LinkedList(java.util.LinkedList) Collections(java.util.Collections) WeakHashMap(java.util.WeakHashMap) CoercionFailedException(org.apache.tapestry5.commons.util.CoercionFailedException) UnknownValueException(org.apache.tapestry5.commons.util.UnknownValueException) CoercionNotFoundException(org.apache.tapestry5.commons.util.CoercionNotFoundException) CoercionTuple(org.apache.tapestry5.commons.services.CoercionTuple)

Example 3 with CoercionTuple

use of org.apache.tapestry5.commons.services.CoercionTuple in project tapestry-5 by apache.

the class EnumValueEncoderTest method roundtrip_with_custom_coercer.

@Test
public // TAP5-2496
void roundtrip_with_custom_coercer() {
    CoercionTuple<Stooge, String> stoogeToString = CoercionTuple.create(Stooge.class, String.class, new Coercion<Stooge, String>() {

        @Override
        public String coerce(Stooge input) {
            return String.valueOf(input.ordinal());
        }
    });
    CoercionTuple<String, Stooge> stringToStooge = CoercionTuple.create(String.class, Stooge.class, new Coercion<String, Stooge>() {

        @Override
        public Stooge coerce(String input) {
            return Stooge.values()[Integer.parseInt(input)];
        }
    });
    Map<CoercionTuple.Key, CoercionTuple> map = new HashMap<>();
    map.put(stoogeToString.getKey(), stoogeToString);
    map.put(stringToStooge.getKey(), stringToStooge);
    TypeCoercer typeCoercer = new TypeCoercerImpl(map);
    EnumValueEncoder<Stooge> encoder = new EnumValueEncoder<Stooge>(typeCoercer, Stooge.class);
    Stooge serverValue = Stooge.LARRY;
    String clientValue = encoder.toClient(serverValue);
    Stooge convertedBack = encoder.toValue(clientValue);
    assertEquals(convertedBack, serverValue);
}
Also used : HashMap(java.util.HashMap) TypeCoercer(org.apache.tapestry5.commons.services.TypeCoercer) CoercionTuple(org.apache.tapestry5.commons.services.CoercionTuple) TypeCoercerImpl(org.apache.tapestry5.commons.internal.services.TypeCoercerImpl) Test(org.testng.annotations.Test)

Example 4 with CoercionTuple

use of org.apache.tapestry5.commons.services.CoercionTuple in project tapestry-5 by apache.

the class BasicTypeCoercions method provideBasicTypeCoercions.

/**
 * Provides the basic type coercions to a {@link MappedConfiguration} instance.
 */
public static void provideBasicTypeCoercions(MappedConfiguration<CoercionTuple.Key, CoercionTuple> configuration) {
    add(configuration, Object.class, String.class, new Coercion<Object, String>() {

        @Override
        public String coerce(Object input) {
            return input.toString();
        }
    });
    add(configuration, Object.class, Boolean.class, new Coercion<Object, Boolean>() {

        @Override
        public Boolean coerce(Object input) {
            return input != null;
        }
    });
    add(configuration, String.class, Double.class, new Coercion<String, Double>() {

        @Override
        public Double coerce(String input) {
            return Double.valueOf(input);
        }
    });
    // String to BigDecimal is important, as String->Double->BigDecimal would lose
    // precision.
    add(configuration, String.class, BigDecimal.class, new Coercion<String, BigDecimal>() {

        @Override
        public BigDecimal coerce(String input) {
            return new BigDecimal(input);
        }
    });
    add(configuration, BigDecimal.class, Double.class, new Coercion<BigDecimal, Double>() {

        @Override
        public Double coerce(BigDecimal input) {
            return input.doubleValue();
        }
    });
    add(configuration, String.class, BigInteger.class, new Coercion<String, BigInteger>() {

        @Override
        public BigInteger coerce(String input) {
            return new BigInteger(input);
        }
    });
    add(configuration, String.class, Long.class, new Coercion<String, Long>() {

        @Override
        public Long coerce(String input) {
            return Long.valueOf(input);
        }
    });
    add(configuration, String.class, Integer.class, Integer::valueOf);
    add(configuration, Long.class, Byte.class, new Coercion<Long, Byte>() {

        @Override
        public Byte coerce(Long input) {
            return input.byteValue();
        }
    });
    add(configuration, Long.class, Short.class, new Coercion<Long, Short>() {

        @Override
        public Short coerce(Long input) {
            return input.shortValue();
        }
    });
    add(configuration, Long.class, Integer.class, new Coercion<Long, Integer>() {

        @Override
        public Integer coerce(Long input) {
            return input.intValue();
        }
    });
    add(configuration, Number.class, Long.class, new Coercion<Number, Long>() {

        @Override
        public Long coerce(Number input) {
            return input.longValue();
        }
    });
    add(configuration, Double.class, Float.class, new Coercion<Double, Float>() {

        @Override
        public Float coerce(Double input) {
            return input.floatValue();
        }
    });
    add(configuration, Long.class, Double.class, new Coercion<Long, Double>() {

        @Override
        public Double coerce(Long input) {
            return input.doubleValue();
        }
    });
    add(configuration, String.class, Boolean.class, new Coercion<String, Boolean>() {

        @Override
        public Boolean coerce(String input) {
            String trimmed = input == null ? "" : input.trim();
            if (trimmed.equalsIgnoreCase("false") || trimmed.length() == 0)
                return false;
            return true;
        }
    });
    add(configuration, Number.class, Boolean.class, new Coercion<Number, Boolean>() {

        @Override
        public Boolean coerce(Number input) {
            return input.longValue() != 0;
        }
    });
    add(configuration, Void.class, Boolean.class, new Coercion<Void, Boolean>() {

        @Override
        public Boolean coerce(Void input) {
            return false;
        }
    });
    add(configuration, Collection.class, Boolean.class, new Coercion<Collection, Boolean>() {

        @Override
        public Boolean coerce(Collection input) {
            return !input.isEmpty();
        }
    });
    add(configuration, Object.class, List.class, new Coercion<Object, List>() {

        @Override
        public List coerce(Object input) {
            return Collections.singletonList(input);
        }
    });
    add(configuration, Object[].class, List.class, new Coercion<Object[], List>() {

        @Override
        public List coerce(Object[] input) {
            return Arrays.asList(input);
        }
    });
    add(configuration, Object[].class, Boolean.class, new Coercion<Object[], Boolean>() {

        @Override
        public Boolean coerce(Object[] input) {
            return input != null && input.length > 0;
        }
    });
    add(configuration, Float.class, Double.class, new Coercion<Float, Double>() {

        @Override
        public Double coerce(Float input) {
            return input.doubleValue();
        }
    });
    Coercion primitiveArrayCoercion = new Coercion<Object, List>() {

        @Override
        public List<Object> coerce(Object input) {
            int length = Array.getLength(input);
            Object[] array = new Object[length];
            for (int i = 0; i < length; i++) {
                array[i] = Array.get(input, i);
            }
            return Arrays.asList(array);
        }
    };
    add(configuration, byte[].class, List.class, primitiveArrayCoercion);
    add(configuration, short[].class, List.class, primitiveArrayCoercion);
    add(configuration, int[].class, List.class, primitiveArrayCoercion);
    add(configuration, long[].class, List.class, primitiveArrayCoercion);
    add(configuration, float[].class, List.class, primitiveArrayCoercion);
    add(configuration, double[].class, List.class, primitiveArrayCoercion);
    add(configuration, char[].class, List.class, primitiveArrayCoercion);
    add(configuration, boolean[].class, List.class, primitiveArrayCoercion);
    add(configuration, String.class, File.class, new Coercion<String, File>() {

        @Override
        public File coerce(String input) {
            return new File(input);
        }
    });
    add(configuration, String.class, TimeInterval.class, new Coercion<String, TimeInterval>() {

        @Override
        public TimeInterval coerce(String input) {
            return new TimeInterval(input);
        }
    });
    add(configuration, TimeInterval.class, Long.class, new Coercion<TimeInterval, Long>() {

        @Override
        public Long coerce(TimeInterval input) {
            return input.milliseconds();
        }
    });
    add(configuration, Object.class, Object[].class, new Coercion<Object, Object[]>() {

        @Override
        public Object[] coerce(Object input) {
            return new Object[] { input };
        }
    });
    add(configuration, Collection.class, Object[].class, new Coercion<Collection, Object[]>() {

        @Override
        public Object[] coerce(Collection input) {
            return input.toArray();
        }
    });
    CoercionTuple<Flow, List> flowToListCoercion = CoercionTuple.create(Flow.class, List.class, Flow::toList);
    configuration.add(flowToListCoercion.getKey(), flowToListCoercion);
    CoercionTuple<Flow, Boolean> flowToBooleanCoercion = CoercionTuple.create(Flow.class, Boolean.class, (i) -> !i.isEmpty());
    configuration.add(flowToBooleanCoercion.getKey(), flowToBooleanCoercion);
}
Also used : List(java.util.List) BigInteger(java.math.BigInteger) Collection(java.util.Collection) File(java.io.File) TimeInterval(org.apache.tapestry5.commons.util.TimeInterval) BigDecimal(java.math.BigDecimal) StringToEnumCoercion(org.apache.tapestry5.commons.util.StringToEnumCoercion) Coercion(org.apache.tapestry5.commons.services.Coercion) Flow(org.apache.tapestry5.func.Flow) BigInteger(java.math.BigInteger)

Example 5 with CoercionTuple

use of org.apache.tapestry5.commons.services.CoercionTuple in project tapestry-5 by apache.

the class TypeCoercerImpl method seedQueue.

/**
 * Seeds the pool with the initial set of coercions for the given type.
 */
private void seedQueue(Class sourceType, Class targetType, Set<CoercionTuple.Key> consideredTuples, LinkedList<CoercionTuple> queue) {
    for (Class c : new InheritanceSearch(sourceType)) {
        List<CoercionTuple> tuples = getTuples(c, targetType);
        if (tuples == null) {
            continue;
        }
        for (CoercionTuple tuple : tuples) {
            queue.addLast(tuple);
            consideredTuples.add(tuple.getKey());
        }
        if (sourceType == Void.class) {
            return;
        }
    }
}
Also used : CoercionTuple(org.apache.tapestry5.commons.services.CoercionTuple) InheritanceSearch(org.apache.tapestry5.commons.internal.util.InheritanceSearch)

Aggregations

CoercionTuple (org.apache.tapestry5.commons.services.CoercionTuple)5 Collection (java.util.Collection)3 List (java.util.List)3 InheritanceSearch (org.apache.tapestry5.commons.internal.util.InheritanceSearch)3 Coercion (org.apache.tapestry5.commons.services.Coercion)3 StringToEnumCoercion (org.apache.tapestry5.commons.util.StringToEnumCoercion)3 Map (java.util.Map)2 TypeCoercer (org.apache.tapestry5.commons.services.TypeCoercer)2 ReadPreference (com.mongodb.ReadPreference)1 WriteConcern (com.mongodb.WriteConcern)1 File (java.io.File)1 BigDecimal (java.math.BigDecimal)1 BigInteger (java.math.BigInteger)1 DateFormat (java.text.DateFormat)1 SimpleDateFormat (java.text.SimpleDateFormat)1 Calendar (java.util.Calendar)1 Collections (java.util.Collections)1 Date (java.util.Date)1 HashMap (java.util.HashMap)1 LinkedList (java.util.LinkedList)1