You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by th...@apache.org on 2014/12/06 23:30:24 UTC
[13/15] tapestry-5 git commit: Fourth pass creating the BeanModel and
Commons packages.
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java
new file mode 100644
index 0000000..49b0b15
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java
@@ -0,0 +1,59 @@
+// Copyright 2008 The Apache Software Foundation
+//
+// 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.apache.tapestry5.ioc.internal.services;
+
+import org.apache.tapestry5.ioc.AnnotationProvider;
+
+import java.lang.annotation.Annotation;
+import java.util.List;
+
+/**
+ * Chain of command for {@link org.apache.tapestry5.ioc.AnnotationProvider}.
+ */
+public class AnnotationProviderChain implements AnnotationProvider
+{
+ private final AnnotationProvider[] providers;
+
+ public AnnotationProviderChain(AnnotationProvider[] providers)
+ {
+ this.providers = providers;
+ }
+
+ /**
+ * Creates an AnnotationProvider from the list of providers. Returns either an {@link AnnotationProviderChain} or
+ * the sole element in the list.
+ */
+ public static AnnotationProvider create(List<AnnotationProvider> providers)
+ {
+ int size = providers.size();
+
+ if (size == 1) return providers.get(0);
+
+ return new AnnotationProviderChain(providers.toArray(new AnnotationProvider[providers.size()]));
+ }
+
+ @Override
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+ {
+ for (AnnotationProvider p : providers)
+ {
+ T result = p.getAnnotation(annotationClass);
+
+ if (result != null) return result;
+ }
+
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java
new file mode 100644
index 0000000..4a5dece
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java
@@ -0,0 +1,54 @@
+// Copyright 2006, 2007 The Apache Software Foundation
+//
+// 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.apache.tapestry5.ioc.internal.services;
+
+import org.apache.tapestry5.ioc.services.Coercion;
+
+/**
+ * Combines two coercions to create a coercion through an intermediate type.
+ *
+ * @param <S> The source (input) type
+ * @param <I> The intermediate type
+ * @param <T> The target (output) type
+ */
+public class CompoundCoercion<S, I, T> implements Coercion<S, T>
+{
+ private final Coercion<S, I> op1;
+
+ private final Coercion<I, T> op2;
+
+ public CompoundCoercion(Coercion<S, I> op1, Coercion<I, T> op2)
+ {
+ this.op1 = op1;
+ this.op2 = op2;
+ }
+
+ @Override
+ public T coerce(S input)
+ {
+ // Run the input through the first operation (S --> I), then run the result of that through
+ // the second operation (I --> T).
+
+ I intermediate = op1.coerce(input);
+
+ return op2.coerce(intermediate);
+ }
+
+ @Override
+ public String toString()
+ {
+ return String.format("%s, %s", op1, op2);
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java
new file mode 100644
index 0000000..e92ef2d
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java
@@ -0,0 +1,68 @@
+// Copyright 2006, 2007, 2011, 2012 The Apache Software Foundation
+//
+// 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.apache.tapestry5.ioc.internal.services;
+
+import org.apache.tapestry5.ioc.Messages;
+import org.apache.tapestry5.ioc.internal.util.MessagesImpl;
+import org.apache.tapestry5.ioc.services.Coercion;
+import org.apache.tapestry5.plastic.PlasticUtils;
+
+public class ServiceMessages
+{
+ private final static Messages MESSAGES = MessagesImpl.forClass(ServiceMessages.class);
+
+ private ServiceMessages()
+ {
+ }
+
+ public static String noSuchProperty(Class clazz, String propertyName)
+ {
+ return MESSAGES.format("no-such-property", clazz.getName(), propertyName);
+ }
+
+
+ public static String readFailure(String propertyName, Object instance, Throwable cause)
+ {
+ return MESSAGES.format("read-failure", propertyName, instance, cause);
+ }
+
+ public static String propertyTypeMismatch(String propertyName, Class sourceClass, Class propertyType,
+ Class expectedType)
+ {
+ return MESSAGES.format("property-type-mismatch", propertyName, sourceClass.getName(), propertyType.getName(),
+ expectedType.getName());
+ }
+
+ public static String shutdownListenerError(Object listener, Throwable cause)
+ {
+ return MESSAGES.format("shutdown-listener-error", listener, cause);
+ }
+
+ public static String failedCoercion(Object input, Class targetType, Coercion coercion, Throwable cause)
+ {
+ return MESSAGES.format("failed-coercion", String.valueOf(input), PlasticUtils.toTypeName(targetType),
+ coercion, cause);
+ }
+
+ public static String registryShutdown(String serviceId)
+ {
+ return MESSAGES.format("registry-shutdown", serviceId);
+ }
+
+ public static String serviceBuildFailure(String serviceId, Throwable cause)
+ {
+ return MESSAGES.format("service-build-failure", serviceId, cause);
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java
new file mode 100644
index 0000000..0769b7e
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java
@@ -0,0 +1,65 @@
+// Copyright 2007 The Apache Software Foundation
+//
+// 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.apache.tapestry5.ioc.internal.services;
+
+import org.apache.tapestry5.ioc.Location;
+import org.apache.tapestry5.ioc.Resource;
+
+/**
+ * Implementation of {@link Location} used when the underlying resource isn't really known.
+ */
+public final class StringLocation implements Location
+{
+ private final String description;
+
+ private final int line;
+
+ public StringLocation(String description, int line)
+ {
+ this.description = description;
+ this.line = line;
+ }
+
+ @Override
+ public String toString()
+ {
+ return description;
+ }
+
+ /**
+ * Returns 0.
+ */
+ @Override
+ public int getColumn()
+ {
+ return 0;
+ }
+
+ @Override
+ public int getLine()
+ {
+ return line;
+ }
+
+ /**
+ * Returns null; we don't know where the file really is (it's probably a class on the class path).
+ */
+ @Override
+ public Resource getResource()
+ {
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
new file mode 100644
index 0000000..6481384
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
@@ -0,0 +1,508 @@
+// Copyright 2006, 2007, 2008, 2010, 2012 The Apache Software Foundation
+//
+// 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.apache.tapestry5.ioc.internal.services;
+
+import org.apache.tapestry5.func.F;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.InheritanceSearch;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
+import org.apache.tapestry5.ioc.internal.util.LockSupport;
+import org.apache.tapestry5.ioc.services.Coercion;
+import org.apache.tapestry5.ioc.services.CoercionTuple;
+import org.apache.tapestry5.ioc.services.TypeCoercer;
+import org.apache.tapestry5.ioc.util.AvailableValues;
+import org.apache.tapestry5.ioc.util.UnknownValueException;
+import org.apache.tapestry5.plastic.PlasticUtils;
+import org.apache.tapestry5.util.StringToEnumCoercion;
+
+import java.util.*;
+
+@SuppressWarnings("all")
+public class TypeCoercerImpl extends LockSupport implements TypeCoercer
+{
+ // Constructed from the service's configuration.
+
+ private final Map<Class, List<CoercionTuple>> sourceTypeToTuple = CollectionFactory.newMap();
+
+ /**
+ * A coercion to a specific target type. Manages a cache of coercions to specific types.
+ */
+ private class TargetCoercion
+ {
+ private final Class type;
+
+ private final Map<Class, Coercion> cache = CollectionFactory.newConcurrentMap();
+
+ TargetCoercion(Class type)
+ {
+ this.type = type;
+ }
+
+ void clearCache()
+ {
+ cache.clear();
+ }
+
+ Object coerce(Object input)
+ {
+ Class sourceType = input != null ? input.getClass() : Void.class;
+
+ if (type.isAssignableFrom(sourceType))
+ {
+ return input;
+ }
+
+ Coercion c = getCoercion(sourceType);
+
+ try
+ {
+ return type.cast(c.coerce(input));
+ } catch (Exception ex)
+ {
+ throw new RuntimeException(ServiceMessages.failedCoercion(input, type, c, ex), ex);
+ }
+ }
+
+ String explain(Class sourceType)
+ {
+ return getCoercion(sourceType).toString();
+ }
+
+ private Coercion getCoercion(Class sourceType)
+ {
+ Coercion c = cache.get(sourceType);
+
+ if (c == null)
+ {
+ c = findOrCreateCoercion(sourceType, type);
+ cache.put(sourceType, c);
+ }
+
+ return c;
+ }
+ }
+
+ /**
+ * Map from a target type to a TargetCoercion for that type.
+ */
+ private final Map<Class, TargetCoercion> typeToTargetCoercion = new WeakHashMap<Class, TargetCoercion>();
+
+ private static final Coercion NO_COERCION = new Coercion<Object, Object>()
+ {
+ @Override
+ public Object coerce(Object input)
+ {
+ return input;
+ }
+ };
+
+ private static final Coercion COERCION_NULL_TO_OBJECT = new Coercion<Void, Object>()
+ {
+ @Override
+ public Object coerce(Void input)
+ {
+ return null;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "null --> null";
+ }
+ };
+
+ public TypeCoercerImpl(Collection<CoercionTuple> tuples)
+ {
+ for (CoercionTuple tuple : tuples)
+ {
+ Class key = tuple.getSourceType();
+
+ InternalCommonsUtils.addToMapList(sourceTypeToTuple, key, tuple);
+ }
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Object coerce(Object input, Class targetType)
+ {
+ assert targetType != null;
+
+ Class effectiveTargetType = PlasticUtils.toWrapperType(targetType);
+
+ if (effectiveTargetType.isInstance(input))
+ {
+ return input;
+ }
+
+
+ return getTargetCoercion(effectiveTargetType).coerce(input);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <S, T> Coercion<S, T> getCoercion(Class<S> sourceType, Class<T> targetType)
+ {
+ assert sourceType != null;
+ assert targetType != null;
+
+ Class effectiveSourceType = PlasticUtils.toWrapperType(sourceType);
+ Class effectiveTargetType = PlasticUtils.toWrapperType(targetType);
+
+ if (effectiveTargetType.isAssignableFrom(effectiveSourceType))
+ {
+ return NO_COERCION;
+ }
+
+ return getTargetCoercion(effectiveTargetType).getCoercion(effectiveSourceType);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <S, T> String explain(Class<S> sourceType, Class<T> targetType)
+ {
+ assert sourceType != null;
+ assert targetType != null;
+
+ Class effectiveTargetType = PlasticUtils.toWrapperType(targetType);
+ Class effectiveSourceType = PlasticUtils.toWrapperType(sourceType);
+
+ // Is a coercion even necessary? Not if the target type is assignable from the
+ // input value.
+
+ if (effectiveTargetType.isAssignableFrom(effectiveSourceType))
+ {
+ return "";
+ }
+
+ return getTargetCoercion(effectiveTargetType).explain(effectiveSourceType);
+ }
+
+ private TargetCoercion getTargetCoercion(Class targetType)
+ {
+ try
+ {
+ acquireReadLock();
+
+ TargetCoercion tc = typeToTargetCoercion.get(targetType);
+
+ return tc != null ? tc : createAndStoreNewTargetCoercion(targetType);
+ } finally
+ {
+ releaseReadLock();
+ }
+ }
+
+ private TargetCoercion createAndStoreNewTargetCoercion(Class targetType)
+ {
+ try
+ {
+ upgradeReadLockToWriteLock();
+
+ // Inner check since some other thread may have beat us to it.
+
+ TargetCoercion tc = typeToTargetCoercion.get(targetType);
+
+ if (tc == null)
+ {
+ tc = new TargetCoercion(targetType);
+ typeToTargetCoercion.put(targetType, tc);
+ }
+
+ return tc;
+ } finally
+ {
+ downgradeWriteLockToReadLock();
+ }
+ }
+
+ @Override
+ public void clearCache()
+ {
+ try
+ {
+ acquireReadLock();
+
+ // There's no need to clear the typeToTargetCoercion map, as it is a WeakHashMap and
+ // will release the keys for classes that are no longer in existence. On the other hand,
+ // there's likely all sorts of references to unloaded classes inside each TargetCoercion's
+ // individual cache, so clear all those.
+
+ for (TargetCoercion tc : typeToTargetCoercion.values())
+ {
+ // Can tc ever be null?
+
+ tc.clearCache();
+ }
+ } finally
+ {
+ releaseReadLock();
+ }
+ }
+
+ /**
+ * 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.
+ * <p/>
+ * 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.
+ * <p/>
+ * 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.
+ * <p/>
+ * 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);
+ }
+
+ // 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> 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);
+ }
+
+ // Not found anywhere. Identify the source and target type and a (sorted) list of
+ // all the known coercions.
+
+ throw new UnknownValueException(String.format("Could not find a coercion from type %s to type %s.",
+ sourceType.getName(), targetType.getName()), buildCoercionCatalog());
+ }
+
+ /**
+ * Coercion from null is special; we match based on the target type and its not a spanning
+ * search. In many cases, we
+ * return a pass-thru that leaves the value as null.
+ *
+ * @param targetType
+ * desired type
+ * @return the coercion
+ */
+ private Coercion searchForNullCoercion(Class targetType)
+ {
+ List<CoercionTuple> tuples = getTuples(Void.class, targetType);
+
+ for (CoercionTuple tuple : tuples)
+ {
+ Class tupleTargetType = tuple.getTargetType();
+
+ if (targetType.equals(tupleTargetType))
+ return tuple.getCoercion();
+ }
+
+ // Typical case: no match, this coercion passes the null through
+ // as null.
+
+ return COERCION_NULL_TO_OBJECT;
+ }
+
+ /**
+ * Builds a string listing all the coercions configured for the type coercer, sorted
+ * alphabetically.
+ */
+ @SuppressWarnings("unchecked")
+ private AvailableValues buildCoercionCatalog()
+ {
+ List<CoercionTuple> masterList = CollectionFactory.newList();
+
+ for (List<CoercionTuple> list : sourceTypeToTuple.values())
+ {
+ masterList.addAll(list);
+ }
+
+ return new AvailableValues("Configured coercions", masterList);
+ }
+
+ /**
+ * Seeds the pool with the initial set of coercions for the given type.
+ */
+ private void seedQueue(Class sourceType, Class targetType, Set<CoercionTuple> consideredTuples,
+ LinkedList<CoercionTuple> queue)
+ {
+ // Work from the source type up looking for tuples
+
+ 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);
+ }
+
+ // Don't pull in Object -> type coercions when doing
+ // a search from null.
+
+ if (sourceType == Void.class)
+ {
+ return;
+ }
+ }
+ }
+
+ /**
+ * 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> consideredTuples, LinkedList<CoercionTuple> queue)
+ {
+ Class intermediateType = intermediateTuple.getTargetType();
+
+ for (Class c : new InheritanceSearch(intermediateType))
+ {
+ for (CoercionTuple tuple : getTuples(c, targetType))
+ {
+ if (consideredTuples.contains(tuple))
+ {
+ continue;
+ }
+
+ Class newIntermediateType = tuple.getTargetType();
+
+ // If this tuple is for coercing from an intermediate type back towards our
+ // initial source type, then ignore it. This should only be an optimization,
+ // as branches that loop back towards the source type will
+ // eventually be considered and discarded.
+
+ 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);
+ }
+ }
+ }
+
+ /**
+ * Returns a non-null list of the tuples from the source type.
+ *
+ * @param sourceType
+ * used to locate tuples
+ * @param targetType
+ * used to add synthetic tuples
+ * @return non-null list of tuples
+ */
+ private List<CoercionTuple> getTuples(Class sourceType, Class targetType)
+ {
+ List<CoercionTuple> tuples = sourceTypeToTuple.get(sourceType);
+
+ if (tuples == null)
+ {
+ tuples = Collections.emptyList();
+ }
+
+ // So, when we see String and an Enum type, we add an additional synthetic tuple to the end
+ // of the real list. This is the easiest way to accomplish this is a thread-safe and class-reloading
+ // safe way (i.e., what if the Enum is defined by a class loader that gets discarded? Don't want to cause
+ // memory leaks by retaining an instance). In any case, there are edge cases where we may create
+ // the tuple unnecessarily (such as when an explicit string-to-enum coercion is part of the TypeCoercer
+ // configuration), but on the whole, this is cheap and works.
+
+ if (sourceType == String.class && Enum.class.isAssignableFrom(targetType))
+ {
+ tuples = extend(tuples, new CoercionTuple(sourceType, targetType, new StringToEnumCoercion(targetType)));
+ }
+
+ return tuples;
+ }
+
+ private static <T> List<T> extend(List<T> list, T extraValue)
+ {
+ return F.flow(list).append(extraValue).toList();
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java
new file mode 100644
index 0000000..f1830a7
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java
@@ -0,0 +1,159 @@
+// Copyright 2006 The Apache Software Foundation
+//
+// 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.apache.tapestry5.ioc.internal.util;
+
+import org.apache.tapestry5.plastic.PlasticUtils;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Set;
+
+/**
+ * Used to search from a particular class up the inheritance hierarchy of extended classes and implemented interfaces.
+ * <p/>
+ * The search starts with the initial class (provided in the constructor). It progresses up the inheritance chain, but
+ * skips java.lang.Object.
+ * <p/>
+ * Once classes are exhausted, the inheritance hierarchy is searched. This is a breadth-first search, rooted in the
+ * interfaces implemented by the initial class at its super classes.
+ * <p/>
+ * Once all interfaces are exhausted, java.lang.Object is returned (it is always returned last).
+ * <p/>
+ * Two minor tweak to normal inheritance rules: <ul> <li> Normally, the parent class of an <em>object</em> array is
+ * java.lang.Object, which is odd because FooService[] is assignable to Object[]. Thus, we tweak the search so that the
+ * effective super class of FooService[] is Object[]. <li> The "super class" of a primtive type is its <em>wrapper type</em>,
+ * with the exception of void, whose "super class" is left at its normal value (Object.class) </ul>
+ * <p/>
+ * This class implements the {@link Iterable} interface, so it can be used directly in a for loop: <code> for (Class
+ * search : new InheritanceSearch(startClass)) { ... } </code>
+ * <p/>
+ * This class is not thread-safe.
+ */
+public class InheritanceSearch implements Iterator<Class>, Iterable<Class>
+{
+ private Class searchClass;
+
+ private final Set<Class> addedInterfaces = CollectionFactory.newSet();
+
+ private final LinkedList<Class> interfaceQueue = CollectionFactory.newLinkedList();
+
+ private enum State
+ {
+ CLASS, INTERFACE, DONE
+ }
+
+ private State state;
+
+ public InheritanceSearch(Class searchClass)
+ {
+ this.searchClass = searchClass;
+
+ queueInterfaces(searchClass);
+
+ state = searchClass == Object.class ? State.INTERFACE : State.CLASS;
+ }
+
+ private void queueInterfaces(Class searchClass)
+ {
+ for (Class intf : searchClass.getInterfaces())
+ {
+ if (addedInterfaces.contains(intf)) continue;
+
+ interfaceQueue.addLast(intf);
+ addedInterfaces.add(intf);
+ }
+ }
+
+ @Override
+ public Iterator<Class> iterator()
+ {
+ return this;
+ }
+
+ @Override
+ public boolean hasNext()
+ {
+ return state != State.DONE;
+ }
+
+ @Override
+ public Class next()
+ {
+ switch (state)
+ {
+ case CLASS:
+
+ Class result = searchClass;
+
+ searchClass = parentOf(searchClass);
+
+ if (searchClass == null) state = State.INTERFACE;
+ else queueInterfaces(searchClass);
+
+ return result;
+
+ case INTERFACE:
+
+ if (interfaceQueue.isEmpty())
+ {
+ state = State.DONE;
+ return Object.class;
+ }
+
+ Class intf = interfaceQueue.removeFirst();
+
+ queueInterfaces(intf);
+
+ return intf;
+
+ default:
+ throw new IllegalStateException();
+ }
+
+ }
+
+ /**
+ * Returns the parent of the given class. Tweaks inheritance for object arrays. Returns null instead of
+ * Object.class.
+ */
+ private Class parentOf(Class clazz)
+ {
+ if (clazz != void.class && clazz.isPrimitive()) return PlasticUtils.toWrapperType(clazz);
+
+ if (clazz.isArray() && clazz != Object[].class)
+ {
+ Class componentType = clazz.getComponentType();
+
+ while (componentType.isArray()) componentType = componentType.getComponentType();
+
+ if (!componentType.isPrimitive()) return Object[].class;
+ }
+
+ Class parent = clazz.getSuperclass();
+
+ return parent != Object.class ? parent : null;
+ }
+
+ /**
+ * @throws UnsupportedOperationException
+ * always
+ */
+ @Override
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java
new file mode 100644
index 0000000..3c391e0
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java
@@ -0,0 +1,388 @@
+// Copyright 2006-2014 The Apache Software Foundation
+//
+// 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.apache.tapestry5.ioc.internal.util;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.tapestry5.ioc.AnnotationProvider;
+import org.apache.tapestry5.ioc.Locatable;
+import org.apache.tapestry5.ioc.Location;
+import org.apache.tapestry5.ioc.Messages;
+import org.apache.tapestry5.ioc.internal.NullAnnotationProvider;
+
+/**
+ * Utility methods class for the Commons package.
+ */
+public class InternalCommonsUtils {
+
+ /**
+ * @since 5.3
+ */
+ public final static AnnotationProvider NULL_ANNOTATION_PROVIDER = new NullAnnotationProvider();
+ private static final Pattern NON_WORD_PATTERN = Pattern.compile("[^\\w]");
+
+ /**
+ * Adds a value to a specially organized map where the values are lists of objects. This somewhat simulates a map
+ * that allows multiple values for the same key.
+ *
+ * @param map
+ * to store value into
+ * @param key
+ * for which a value is added
+ * @param value
+ * to add
+ * @param <K>
+ * the type of key
+ * @param <V>
+ * the type of the list
+ */
+ public static <K, V> void addToMapList(Map<K, List<V>> map, K key, V value)
+ {
+ List<V> list = map.get(key);
+
+ if (list == null)
+ {
+ list = CollectionFactory.newList();
+ map.put(key, list);
+ }
+
+ list.add(value);
+ }
+
+ /**
+ * Sniffs the object to see if it is a {@link Location} or {@link Locatable}. Returns null if null or not
+ * convertable to a location.
+ */
+
+ public static Location locationOf(Object location)
+ {
+ if (location == null)
+ return null;
+
+ if (location instanceof Location)
+ return (Location) location;
+
+ if (location instanceof Locatable)
+ return ((Locatable) location).getLocation();
+
+ return null;
+ }
+
+ public static AnnotationProvider toAnnotationProvider(final Method element)
+ {
+ if (element == null)
+ return NULL_ANNOTATION_PROVIDER;
+
+ return new AnnotationProvider()
+ {
+ @Override
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+ {
+ return element.getAnnotation(annotationClass);
+ }
+ };
+ }
+
+ /**
+ * Used to convert a property expression into a key that can be used to locate various resources (Blocks, messages,
+ * etc.). Strips out any punctuation characters, leaving just words characters (letters, number and the
+ * underscore).
+ *
+ * @param expression a property expression
+ * @return the expression with punctuation removed
+ */
+ public static String extractIdFromPropertyExpression(String expression)
+ {
+ return replace(expression, NON_WORD_PATTERN, "");
+ }
+
+ public static String replace(String input, Pattern pattern, String replacement)
+ {
+ return pattern.matcher(input).replaceAll(replacement);
+ }
+
+ /**
+ * Looks for a label within the messages based on the id. If found, it is used, otherwise the name is converted to a
+ * user presentable form.
+ */
+ public static String defaultLabel(String id, Messages messages, String propertyExpression)
+ {
+ String key = id + "-label";
+
+ if (messages.contains(key))
+ return messages.get(key);
+
+ return toUserPresentable(extractIdFromPropertyExpression(InternalCommonsUtils.lastTerm(propertyExpression)));
+ }
+
+ /**
+ * Capitalizes the string, and inserts a space before each upper case character (or sequence of upper case
+ * characters). Thus "userId" becomes "User Id", etc. Also, converts underscore into space (and capitalizes the
+ * following word), thus "user_id" also becomes "User Id".
+ */
+ public static String toUserPresentable(String id)
+ {
+ StringBuilder builder = new StringBuilder(id.length() * 2);
+
+ char[] chars = id.toCharArray();
+ boolean postSpace = true;
+ boolean upcaseNext = true;
+
+ for (char ch : chars)
+ {
+ if (upcaseNext)
+ {
+ builder.append(Character.toUpperCase(ch));
+ upcaseNext = false;
+
+ continue;
+ }
+
+ if (ch == '_')
+ {
+ builder.append(' ');
+ upcaseNext = true;
+ continue;
+ }
+
+ boolean upperCase = Character.isUpperCase(ch);
+
+ if (upperCase && !postSpace)
+ builder.append(' ');
+
+ builder.append(ch);
+
+ postSpace = upperCase;
+ }
+
+ return builder.toString();
+ }
+
+ /**
+ * @since 5.3
+ */
+ public static AnnotationProvider toAnnotationProvider(final Class element)
+ {
+ return new AnnotationProvider()
+ {
+ @Override
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+ {
+ return annotationClass.cast(element.getAnnotation(annotationClass));
+ }
+ };
+ }
+
+ /**
+ * Pattern used to eliminate leading and trailing underscores and dollar signs.
+ */
+ static final Pattern NAME_PATTERN = Pattern.compile("^[_|$]*([\\p{javaJavaIdentifierPart}]+?)[_|$]*$",
+ Pattern.CASE_INSENSITIVE);
+
+ /**
+ * Converts a method to a user presentable string consisting of the containing class name, the method name, and the
+ * short form of the parameter list (the class name of each parameter type, shorn of the package name portion).
+ *
+ * @param method
+ * @return short string representation
+ */
+ public static String asString(Method method)
+ {
+ StringBuilder buffer = new StringBuilder();
+
+ buffer.append(method.getDeclaringClass().getName());
+ buffer.append(".");
+ buffer.append(method.getName());
+ buffer.append("(");
+
+ for (int i = 0; i < method.getParameterTypes().length; i++)
+ {
+ if (i > 0)
+ buffer.append(", ");
+
+ String name = method.getParameterTypes()[i].getSimpleName();
+
+ buffer.append(name);
+ }
+
+ return buffer.append(")").toString();
+ }
+
+ /**
+ * Strips leading "_" and "$" and trailing "_" from the name.
+ */
+ public static String stripMemberName(String memberName)
+ {
+ assert InternalCommonsUtils.isNonBlank(memberName);
+ Matcher matcher = NAME_PATTERN.matcher(memberName);
+
+ if (!matcher.matches())
+ throw new IllegalArgumentException(String.format("Input '%s' is not a valid Java identifier.", memberName));
+
+ return matcher.group(1);
+ }
+
+ /**
+ * Joins together some number of elements to form a comma separated list.
+ */
+ public static String join(List elements)
+ {
+ return InternalCommonsUtils.join(elements, ", ");
+ }
+
+ /**
+ * Joins together some number of elements. If a value in the list is the empty string, it is replaced with the
+ * string "(blank)".
+ *
+ * @param elements
+ * objects to be joined together
+ * @param separator
+ * used between elements when joining
+ */
+ public static String join(List elements, String separator)
+ {
+ switch (elements.size())
+ {
+ case 0:
+ return "";
+
+ case 1:
+ return elements.get(0).toString();
+
+ default:
+
+ StringBuilder buffer = new StringBuilder();
+ boolean first = true;
+
+ for (Object o : elements)
+ {
+ if (!first)
+ buffer.append(separator);
+
+ String string = String.valueOf(o);
+
+ if (string.equals(""))
+ string = "(blank)";
+
+ buffer.append(string);
+
+ first = false;
+ }
+
+ return buffer.toString();
+ }
+ }
+
+ /**
+ * Creates a sorted copy of the provided elements, then turns that into a comma separated list.
+ *
+ * @return the elements converted to strings, sorted, joined with comma ... or "(none)" if the elements are null or
+ * empty
+ */
+ public static String joinSorted(Collection elements)
+ {
+ if (elements == null || elements.isEmpty())
+ return "(none)";
+
+ List<String> list = CollectionFactory.newList();
+
+ for (Object o : elements)
+ list.add(String.valueOf(o));
+
+ Collections.sort(list);
+
+ return join(list);
+ }
+
+ /**
+ * Returns true if the input is null, or is a zero length string (excluding leading/trailing whitespace).
+ */
+
+ public static boolean isBlank(String input)
+ {
+ return input == null || input.length() == 0 || input.trim().length() == 0;
+ }
+
+ /**
+ * Capitalizes a string, converting the first character to uppercase.
+ */
+ public static String capitalize(String input)
+ {
+ if (input.length() == 0)
+ return input;
+
+ return input.substring(0, 1).toUpperCase() + input.substring(1);
+ }
+
+ public static boolean isNonBlank(String input)
+ {
+ return !isBlank(input);
+ }
+
+ /**
+ * Return true if the input string contains the marker for symbols that must be expanded.
+ */
+ public static boolean containsSymbols(String input)
+ {
+ return input.contains("${");
+ }
+
+ /**
+ * Searches the string for the final period ('.') character and returns everything after that. The input string is
+ * generally a fully qualified class name, though tapestry-core also uses this method for the occasional property
+ * expression (which is also dot separated). Returns the input string unchanged if it does not contain a period
+ * character.
+ */
+ public static String lastTerm(String input)
+ {
+ assert isNonBlank(input);
+ int dotx = input.lastIndexOf('.');
+
+ if (dotx < 0)
+ return input;
+
+ return input.substring(dotx + 1);
+ }
+
+ /**
+ * Extracts the string keys from a map and returns them in sorted order. The keys are converted to strings.
+ *
+ * @param map
+ * the map to extract keys from (may be null)
+ * @return the sorted keys, or the empty set if map is null
+ */
+
+ public static List<String> sortedKeys(Map map)
+ {
+ if (map == null)
+ return Collections.emptyList();
+
+ List<String> keys = CollectionFactory.newList();
+
+ for (Object o : map.keySet())
+ keys.add(String.valueOf(o));
+
+ Collections.sort(keys);
+
+ return keys;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalStringUtils.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalStringUtils.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalStringUtils.java
deleted file mode 100644
index e345593..0000000
--- a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalStringUtils.java
+++ /dev/null
@@ -1,203 +0,0 @@
-// Copyright 2006-2014 The Apache Software Foundation
-//
-// 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.apache.tapestry5.ioc.internal.util;
-
-import java.lang.reflect.Method;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * String-related utilities used within various internal implementations of the Apache Tapestry subprojects.
- * Broken off Tapestry-IoC's InternalUtils.
- */
-@SuppressWarnings("all")
-public class InternalStringUtils
-{
-
- /**
- * Pattern used to eliminate leading and trailing underscores and dollar signs.
- */
- private static final Pattern NAME_PATTERN = Pattern.compile("^[_|$]*([\\p{javaJavaIdentifierPart}]+?)[_|$]*$",
- Pattern.CASE_INSENSITIVE);
-
- /**
- * Converts a method to a user presentable string consisting of the containing class name, the method name, and the
- * short form of the parameter list (the class name of each parameter type, shorn of the package name portion).
- *
- * @param method
- * @return short string representation
- */
- public static String asString(Method method)
- {
- StringBuilder buffer = new StringBuilder();
-
- buffer.append(method.getDeclaringClass().getName());
- buffer.append(".");
- buffer.append(method.getName());
- buffer.append("(");
-
- for (int i = 0; i < method.getParameterTypes().length; i++)
- {
- if (i > 0)
- buffer.append(", ");
-
- String name = method.getParameterTypes()[i].getSimpleName();
-
- buffer.append(name);
- }
-
- return buffer.append(")").toString();
- }
-
- /**
- * Strips leading "_" and "$" and trailing "_" from the name.
- */
- public static String stripMemberName(String memberName)
- {
- assert isNonBlank(memberName);
- Matcher matcher = NAME_PATTERN.matcher(memberName);
-
- if (!matcher.matches())
- throw new IllegalArgumentException(String.format("Input '%s' is not a valid Java identifier.", memberName));
-
- return matcher.group(1);
- }
-
- /**
- * Joins together some number of elements to form a comma separated list.
- */
- public static String join(List elements)
- {
- return join(elements, ", ");
- }
-
- /**
- * Joins together some number of elements. If a value in the list is the empty string, it is replaced with the
- * string "(blank)".
- *
- * @param elements
- * objects to be joined together
- * @param separator
- * used between elements when joining
- */
- public static String join(List elements, String separator)
- {
- switch (elements.size())
- {
- case 0:
- return "";
-
- case 1:
- return elements.get(0).toString();
-
- default:
-
- StringBuilder buffer = new StringBuilder();
- boolean first = true;
-
- for (Object o : elements)
- {
- if (!first)
- buffer.append(separator);
-
- String string = String.valueOf(o);
-
- if (string.equals(""))
- string = "(blank)";
-
- buffer.append(string);
-
- first = false;
- }
-
- return buffer.toString();
- }
- }
-
- /**
- * Creates a sorted copy of the provided elements, then turns that into a comma separated list.
- *
- * @return the elements converted to strings, sorted, joined with comma ... or "(none)" if the elements are null or
- * empty
- */
- public static String joinSorted(Collection elements)
- {
- if (elements == null || elements.isEmpty())
- return "(none)";
-
- List<String> list = CollectionFactory.newList();
-
- for (Object o : elements)
- list.add(String.valueOf(o));
-
- Collections.sort(list);
-
- return join(list);
- }
-
- /**
- * Returns true if the input is null, or is a zero length string (excluding leading/trailing whitespace).
- */
-
- public static boolean isBlank(String input)
- {
- return input == null || input.length() == 0 || input.trim().length() == 0;
- }
-
- public static boolean isNonBlank(String input)
- {
- return !isBlank(input);
- }
-
- /**
- * Capitalizes a string, converting the first character to uppercase.
- */
- public static String capitalize(String input)
- {
- if (input.length() == 0)
- return input;
-
- return input.substring(0, 1).toUpperCase() + input.substring(1);
- }
-
- /**
- * Return true if the input string contains the marker for symbols that must be expanded.
- */
- public static boolean containsSymbols(String input)
- {
- return input.contains("${");
- }
-
- /**
- * Searches the string for the final period ('.') character and returns everything after that. The input string is
- * generally a fully qualified class name, though tapestry-core also uses this method for the occasional property
- * expression (which is also dot separated). Returns the input string unchanged if it does not contain a period
- * character.
- */
- public static String lastTerm(String input)
- {
- assert isNonBlank(input);
- int dotx = input.lastIndexOf('.');
-
- if (dotx < 0)
- return input;
-
- return input.substring(dotx + 1);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java
new file mode 100644
index 0000000..41de363
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java
@@ -0,0 +1,89 @@
+// Copyright 2012 The Apache Software Foundation
+//
+// 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.apache.tapestry5.ioc.internal.util;
+
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * Base class for classes that need to manage a ReadWriteLock.
+ */
+public abstract class LockSupport
+{
+ private final Lock readLock, writeLock;
+
+ protected LockSupport()
+ {
+ ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
+
+ readLock = lock.readLock();
+ writeLock = lock.writeLock();
+ }
+
+ /**
+ * Locks the shared read lock. Any number of threads may lock the read lock at the same time.
+ */
+ protected final void acquireReadLock()
+ {
+ readLock.lock();
+ }
+
+ /**
+ * Takes the exclusive write lock. Once started, no other thread lock the read or write lock. When this method returns,
+ * this thread will have locked the write lock and no other thread will have either the read or write lock.
+ * Note that this thread must first drop the read lock (if it has it) before attempting to take the write lock, or this method will block forever.
+ */
+ protected final void takeWriteLock()
+ {
+ writeLock.lock();
+ }
+
+ /**
+ * Releases the shared read lock.
+ */
+ protected final void releaseReadLock()
+ {
+ readLock.unlock();
+ }
+
+ /**
+ * Releases the exclusive read lock.
+ */
+ protected final void releaseWriteLock()
+ {
+ writeLock.unlock();
+ }
+
+ /**
+ * Releases the read lock, then takes the write lock. There's a short window where the thread will have neither lock:
+ * during that window, some other thread may have a chance to take the write lock. In code, you'll often see a second check
+ * inside the code that has the write lock to see if the update to perform is still necessary.
+ */
+ protected final void upgradeReadLockToWriteLock()
+ {
+ releaseReadLock();
+ // This is that instant where another thread may grab the write lock. Very rare, but possible.
+ takeWriteLock();
+ }
+
+ /**
+ * Takes the read lock then releases the write lock.
+ */
+ protected final void downgradeWriteLockToReadLock()
+ {
+ acquireReadLock();
+ releaseWriteLock();
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessageFormatterImpl.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessageFormatterImpl.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessageFormatterImpl.java
new file mode 100644
index 0000000..f4d8949
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessageFormatterImpl.java
@@ -0,0 +1,65 @@
+// Copyright 2006-2013 The Apache Software Foundation
+//
+// 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.apache.tapestry5.ioc.internal.util;
+
+import org.apache.tapestry5.ioc.MessageFormatter;
+import org.apache.tapestry5.ioc.util.ExceptionUtils;
+
+import java.util.Locale;
+
+
+public class MessageFormatterImpl implements MessageFormatter
+{
+ private final String format;
+
+ private final Locale locale;
+
+ public MessageFormatterImpl(String format, Locale locale)
+ {
+ this.format = format;
+ this.locale = locale;
+ }
+
+ @Override
+ public String format(Object... args)
+ {
+ for (int i = 0; i < args.length; i++)
+ {
+ Object arg = args[i];
+
+ if (Throwable.class.isInstance(arg))
+ {
+ args[i] = ExceptionUtils.toMessage((Throwable) arg);
+ }
+ }
+
+ // Might be tempting to create a Formatter object and just keep reusing it ... but
+ // Formatters are not threadsafe.
+
+ return String.format(locale, format, args);
+ }
+
+ /**
+ * Returns the underlying format string for this formatter.
+ *
+ * @since 5.4
+ */
+ @Override
+ public String toString()
+ {
+ return format;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java
new file mode 100644
index 0000000..c06ef90
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java
@@ -0,0 +1,74 @@
+// Copyright 2006, 2012 The Apache Software Foundation
+//
+// 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.apache.tapestry5.ioc.internal.util;
+
+import org.apache.tapestry5.ioc.Messages;
+import org.apache.tapestry5.ioc.util.AbstractMessages;
+
+import java.util.*;
+
+/**
+ * Implementation of {@link org.apache.tapestry5.ioc.Messages} based around a {@link java.util.ResourceBundle}.
+ */
+public class MessagesImpl extends AbstractMessages
+{
+ private final Map<String, String> properties = CollectionFactory.newCaseInsensitiveMap();
+
+ /**
+ * Finds the messages for a given Messages utility class. Strings the trailing "Messages" and replaces it with
+ * "Strings" to form the base path. Loads the bundle using the default locale, and the class' class loader.
+ *
+ * @param forClass
+ * @return Messages for the class
+ */
+ public static Messages forClass(Class forClass)
+ {
+ String className = forClass.getName();
+ String stringsClassName = className.replaceAll("Messages$", "Strings");
+
+ Locale locale = Locale.getDefault();
+
+ ResourceBundle bundle = ResourceBundle.getBundle(stringsClassName, locale, forClass.getClassLoader());
+
+ return new MessagesImpl(locale, bundle);
+ }
+
+ public MessagesImpl(Locale locale, ResourceBundle bundle)
+ {
+ super(locale);
+
+ // Our best (threadsafe) chance to determine all the available keys.
+ Enumeration<String> e = bundle.getKeys();
+ while (e.hasMoreElements())
+ {
+ String key = e.nextElement();
+ String value = bundle.getString(key);
+
+ properties.put(key, value);
+ }
+ }
+
+ @Override
+ protected String valueForKey(String key)
+ {
+ return properties.get(key);
+ }
+
+ @Override
+ public Set<String> getKeys()
+ {
+ return properties.keySet();
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
index d8d8018..6e23c5b 100644
--- a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
@@ -34,7 +34,7 @@ public class TapestryException extends RuntimeException implements Locatable
*/
public TapestryException(String message, Object location, Throwable cause)
{
- this(message, locationOf(location), cause);
+ this(message, InternalCommonsUtils.locationOf(location), cause);
}
/**
@@ -71,26 +71,5 @@ public class TapestryException extends RuntimeException implements Locatable
return String.format("%s [at %s]", super.toString(), location);
}
-
- /**
- * Sniffs the object to see if it is a {@link Location} or {@link Locatable}. Returns null if null or not
- * convertable to a location.
- * Copied from InternalUtils to avoid having it moved to BeanModel or Commons subprojects.
- */
-
- private static Location locationOf(Object location)
- {
- if (location == null)
- return null;
-
- if (location instanceof Location)
- return (Location) location;
-
- if (location instanceof Locatable)
- return ((Locatable) location).getLocation();
-
- return null;
- }
-
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/util/AbstractMessages.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/AbstractMessages.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/AbstractMessages.java
new file mode 100644
index 0000000..590c337
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/AbstractMessages.java
@@ -0,0 +1,94 @@
+// Copyright 2006, 2009, 2011 The Apache Software Foundation
+//
+// 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.apache.tapestry5.ioc.util;
+
+import org.apache.tapestry5.ioc.MessageFormatter;
+import org.apache.tapestry5.ioc.Messages;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.MessageFormatterImpl;
+
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * Abstract implementation of {@link Messages} that doesn't know where values come from (that information is supplied in
+ * a subclass, via the {@link #valueForKey(String)} method).
+ */
+public abstract class AbstractMessages implements Messages
+{
+ /**
+ * String key to MF instance.
+ */
+ private final Map<String, MessageFormatter> cache = CollectionFactory.newConcurrentMap();
+
+ private final Locale locale;
+
+ protected AbstractMessages(Locale locale)
+ {
+ this.locale = locale;
+ }
+
+ /**
+ * Invoked to provide the value for a particular key. This may be invoked multiple times even for the same key. The
+ * implementation should <em>ignore the case of the key</em>.
+ *
+ * @param key the key to obtain a value for (case insensitive)
+ * @return the value for the key, or null if this instance can not provide the value
+ */
+ protected abstract String valueForKey(String key);
+
+
+ @Override
+ public boolean contains(String key)
+ {
+ return valueForKey(key) != null;
+ }
+
+ @Override
+ public String get(String key)
+ {
+ if (contains(key)) return valueForKey(key);
+
+ return String.format("[[missing key: %s]]", key);
+ }
+
+ @Override
+ public MessageFormatter getFormatter(String key)
+ {
+ MessageFormatter result = cache.get(key);
+
+ if (result == null)
+ {
+ result = buildMessageFormatter(key);
+ cache.put(key, result);
+ }
+
+ return result;
+ }
+
+ private MessageFormatter buildMessageFormatter(String key)
+ {
+ String format = get(key);
+
+ return new MessageFormatterImpl(format, locale);
+ }
+
+ @Override
+ public String format(String key, Object... args)
+ {
+ return getFormatter(key).format(args);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
index 8c9cb3f..b2f1386 100644
--- a/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
@@ -20,7 +20,7 @@ import java.util.List;
import java.util.Map;
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
/**
* Used (as part of a {@link UnknownValueException} to identify what available values
@@ -81,7 +81,7 @@ public class AvailableValues
@Override
public String toString()
{
- return String.format("AvailableValues[%s: %s]", valueType, InternalStringUtils.join(values));
+ return String.format("AvailableValues[%s: %s]", valueType, InternalCommonsUtils.join(values));
}
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/util/TimeInterval.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/TimeInterval.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/TimeInterval.java
new file mode 100644
index 0000000..01ef99e
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/TimeInterval.java
@@ -0,0 +1,195 @@
+// Copyright 2007, 2008, 2010, 2011 The Apache Software Foundation
+//
+// 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.apache.tapestry5.ioc.util;
+
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
+
+/**
+ * Used to represent a period of time, specifically as a configuration value. This is often used to specify timeouts.
+ * <p/>
+ * TimePeriods are parsed from strings.
+ * <p/>
+ * The string specifys a number of terms. The values of all the terms are summed together to form the total time period.
+ * Each term consists of a number followed by a unit. Units (from largest to smallest) are: <dl> <dt>y <dd>year <dt>d
+ * <dd>day <dt>h <dd>hour <dt>m <dd>minute <dt>s <dd>second <dt>ms <dd>millisecond </dl> <p> Example: "2 h 30 m". By
+ * convention, terms are specified largest to smallest. A term without a unit is assumed to be milliseconds. Units are
+ * case insensitive ("h" or "H" are treated the same).
+ */
+public class TimeInterval
+{
+ private static final Map<String, Long> UNITS = CollectionFactory.newCaseInsensitiveMap();
+
+ private static final long MILLISECOND = 1000l;
+
+ static
+ {
+ UNITS.put("ms", 1l);
+ UNITS.put("s", MILLISECOND);
+ UNITS.put("m", 60 * MILLISECOND);
+ UNITS.put("h", 60 * UNITS.get("m"));
+ UNITS.put("d", 24 * UNITS.get("h"));
+ UNITS.put("y", 365 * UNITS.get("d"));
+ }
+
+ /**
+ * The unit keys, sorted in descending order.
+ */
+ private static final String[] UNIT_KEYS =
+ { "y", "d", "h", "m", "s", "ms" };
+
+ private static final Pattern PATTERN = Pattern.compile("\\s*(\\d+)\\s*([a-z]*)", Pattern.CASE_INSENSITIVE);
+
+ private final long milliseconds;
+
+ /**
+ * Creates a TimeInterval for a string.
+ *
+ * @param input
+ * the string specifying the amount of time in the period
+ */
+ public TimeInterval(String input)
+ {
+ this(parseMilliseconds(input));
+ }
+
+ public TimeInterval(long milliseconds)
+ {
+ this.milliseconds = milliseconds;
+ }
+
+ public long milliseconds()
+ {
+ return milliseconds;
+ }
+
+ public long seconds()
+ {
+ return milliseconds / MILLISECOND;
+ }
+
+ /**
+ * Converts the milliseconds back into a string (compatible with {@link #TimeInterval(String)}).
+ *
+ * @since 5.2.0
+ */
+ public String toDescription()
+ {
+ StringBuilder builder = new StringBuilder();
+
+ String sep = "";
+
+ long remainder = milliseconds;
+
+ for (String key : UNIT_KEYS)
+ {
+ if (remainder == 0)
+ break;
+
+ long value = UNITS.get(key);
+
+ long units = remainder / value;
+
+ if (units > 0)
+ {
+ builder.append(sep);
+ builder.append(units);
+ builder.append(key);
+
+ sep = " ";
+
+ remainder = remainder % value;
+ }
+ }
+
+ return builder.toString();
+ }
+
+ static long parseMilliseconds(String input)
+ {
+ long milliseconds = 0l;
+
+ Matcher matcher = PATTERN.matcher(input);
+
+ matcher.useAnchoringBounds(true);
+
+ // TODO: Notice non matching characters and reject input, including at end
+
+ int lastMatchEnd = -1;
+
+ while (matcher.find())
+ {
+ int start = matcher.start();
+
+ if (lastMatchEnd + 1 < start)
+ {
+ String invalid = input.substring(lastMatchEnd + 1, start);
+ throw new RuntimeException(String.format("Unexpected string '%s' (in time interval '%s').", invalid, input));
+ }
+
+ lastMatchEnd = matcher.end();
+
+ long count = Long.parseLong(matcher.group(1));
+ String units = matcher.group(2);
+
+ if (units.length() == 0)
+ {
+ milliseconds += count;
+ continue;
+ }
+
+ Long unitValue = UNITS.get(units);
+
+ if (unitValue == null)
+ throw new RuntimeException(String.format("Unknown time interval unit '%s' (in '%s'). Defined units: %s.", units, input, InternalCommonsUtils.joinSorted(UNITS.keySet())));
+
+ milliseconds += count * unitValue;
+ }
+
+ if (lastMatchEnd + 1 < input.length())
+ {
+ String invalid = input.substring(lastMatchEnd + 1);
+ throw new RuntimeException(String.format("Unexpected string '%s' (in time interval '%s').", invalid, input));
+ }
+
+ return milliseconds;
+ }
+
+ @Override
+ public String toString()
+ {
+ return String.format("TimeInterval[%d ms]", milliseconds);
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (obj == null)
+ return false;
+
+ if (obj instanceof TimeInterval)
+ {
+ TimeInterval tp = (TimeInterval) obj;
+
+ return milliseconds == tp.milliseconds;
+ }
+
+ return false;
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/util/StringToEnumCoercion.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/util/StringToEnumCoercion.java b/commons/src/main/java/org/apache/tapestry5/util/StringToEnumCoercion.java
new file mode 100644
index 0000000..bdde866
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/util/StringToEnumCoercion.java
@@ -0,0 +1,91 @@
+// Copyright 2007, 2008, 2010, 2011 The Apache Software Foundation
+//
+// 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.apache.tapestry5.util;
+
+import java.util.Map;
+
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
+import org.apache.tapestry5.ioc.services.Coercion;
+import org.apache.tapestry5.ioc.util.AvailableValues;
+import org.apache.tapestry5.ioc.util.UnknownValueException;
+
+/**
+ * A {@link org.apache.tapestry5.ioc.services.Coercion} for converting strings into an instance of a particular
+ * enumerated type. The {@link Enum#name() name} is used as the key to identify the enum instance, in a case-insensitive
+ * fashion.
+ * <p>
+ * Moved from tapestry-core to tapestry-ioc is release 5.3, but kept in same package for compatibility.
+ *
+ * @param <T>
+ * the type of enumeration
+ */
+public final class StringToEnumCoercion<T extends Enum> implements Coercion<String, T>
+{
+ private final Class<T> enumClass;
+
+ private final Map<String, T> stringToEnum = CollectionFactory.newCaseInsensitiveMap();
+
+ public StringToEnumCoercion(Class<T> enumClass)
+ {
+ this(enumClass, enumClass.getEnumConstants());
+ }
+
+ public StringToEnumCoercion(Class<T> enumClass, T... values)
+ {
+ this.enumClass = enumClass;
+
+ for (T value : values)
+ stringToEnum.put(value.name(), value);
+ }
+
+ @Override
+ public T coerce(String input)
+ {
+ if (InternalCommonsUtils.isBlank(input))
+ return null;
+
+ T result = stringToEnum.get(input);
+
+ if (result == null)
+ {
+ String message = String.format("Input '%s' does not identify a value from enumerated type %s.", input,
+ enumClass.getName());
+
+ throw new UnknownValueException(message, new AvailableValues(enumClass.getName() + " enum constants",
+ stringToEnum));
+ }
+
+ return result;
+ }
+
+ /**
+ * Allows an alias value (alternate) string to reference a value.
+ *
+ * @since 5.2.2
+ */
+ public StringToEnumCoercion<T> addAlias(String alias, T value)
+ {
+ stringToEnum.put(alias, value);
+
+ return this;
+ }
+
+ public static <T extends Enum> StringToEnumCoercion<T> create(Class<T> enumClass)
+ {
+ return new StringToEnumCoercion<T>(enumClass);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
index e69377f..e032975 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
@@ -59,7 +59,7 @@ public class TapestryInternalUtils
*/
public static String toUserPresentable(String id)
{
- return InternalBeanModelUtils.toUserPresentable(id);
+ return InternalUtils.toUserPresentable(id);
}
public static Map<String, String> mapFromKeysAndValues(String... keysAndValues)
@@ -228,7 +228,7 @@ public class TapestryInternalUtils
*/
public static String extractIdFromPropertyExpression(String expression)
{
- return InternalBeanModelUtils.extractIdFromPropertyExpression(expression);
+ return InternalUtils.extractIdFromPropertyExpression(expression);
}
/**
@@ -237,7 +237,7 @@ public class TapestryInternalUtils
*/
public static String defaultLabel(String id, Messages messages, String propertyExpression)
{
- return InternalBeanModelUtils.defaultLabel(id, messages, propertyExpression);
+ return InternalUtils.defaultLabel(id, messages, propertyExpression);
}
/**
@@ -304,7 +304,7 @@ public class TapestryInternalUtils
private static String replace(String input, Pattern pattern, String replacement)
{
- return InternalBeanModelUtils.replace(input, pattern, replacement);
+ return InternalUtils.replace(input, pattern, replacement);
}
/**
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StringInternerImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StringInternerImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StringInternerImpl.java
deleted file mode 100644
index 43519dc..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StringInternerImpl.java
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2009, 2012 The Apache Software Foundation
-//
-// 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.apache.tapestry5.internal.services;
-
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.services.ComponentClasses;
-import org.apache.tapestry5.services.InvalidationEventHub;
-
-import javax.annotation.PostConstruct;
-import java.util.Map;
-
-public class StringInternerImpl implements StringInterner
-{
- private final Map<String, String> cache = CollectionFactory.newConcurrentMap();
-
- @PostConstruct
- public void setupInvalidation(@ComponentClasses InvalidationEventHub hub)
- {
- hub.clearOnInvalidation(cache);
- }
-
- public String intern(String string)
- {
- String result = cache.get(string);
-
- // Not yet in the cache? Add it.
-
- if (result == null)
- {
- cache.put(string, string);
- result = string;
- }
-
- return result;
- }
-
- public String format(String format, Object... arguments)
- {
- return intern(String.format(format, arguments));
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Configuration.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Configuration.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Configuration.java
deleted file mode 100644
index 03814f5..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Configuration.java
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2006, 2008, 2009 The Apache Software Foundation
-//
-// 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.apache.tapestry5.ioc;
-
-/**
- * Object passed into a service contributor method that allows the method provide contributed values to the service's
- * configuration.
- * <p/>
- * A service can <em>collect</em> contributions in three different ways:
- * <ul>
- * <li>As an un-ordered collection of values</li>
- * <li>As an ordered list of values (where each value has a unique id, pre-requisites and post-requisites)</li>
- * <li>As a map of keys and values
- * </ul>
- * <p/>
- * This implementation is used for un-ordered configuration data.
- * <p/>
- * The service defines the <em>type</em> of contribution, in terms of a base class or service interface. Contributions
- * must be compatible with the type.
- */
-public interface Configuration<T>
-{
- /**
- * Adds an object to the service's contribution.
- *
- * @param object
- * to add to the service's configuration
- */
- void add(T object);
-
- /**
- * Automatically instantiates an instance of the class, with dependencies injected, and adds it to the
- * configuration. When the configuration type is an interface and the class to be contributed is a local file,
- * then a reloadable proxy for the class will be created and contributed.
- *
- * @param clazz
- * what class to instantiate
- * @since 5.1.0.0
- */
- void addInstance(Class<? extends T> clazz);
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MappedConfiguration.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MappedConfiguration.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MappedConfiguration.java
deleted file mode 100644
index 47c6026..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MappedConfiguration.java
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2006, 2008, 2009, 2010 The Apache Software Foundation
-//
-// 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.apache.tapestry5.ioc;
-
-/**
- * Object passed into a service contributor method that allows the method provide contributed values to the service's
- * configuration.
- * <p/>
- * A service can <em>collect</em> contributions in three different ways:
- * <ul>
- * <li>As an un-ordered collection of values</li>
- * <li>As an ordered list of values (where each value has a unique id, pre-requisites and post-requisites)</li>
- * <li>As a map of keys and values
- * </ul>
- * <p/>
- * The service defines the <em>type</em> of contribution, in terms of a base class or service interface. Contributions
- * must be compatible with the type.
- */
-public interface MappedConfiguration<K, V>
-{
-
- /**
- * Adds a keyed object to the service's contribution.
- *
- * @param key
- * unique id for the value
- * @param value
- * to contribute
- * @throws IllegalArgumentException
- * if key is not unique
- */
- void add(K key, V value);
-
- /**
- * Overrides an existing contribution by its key.
- *
- * @param key
- * unique id of value to override
- * @param value
- * new value, or null to remove the key entirely
- * @since 5.1.0.0
- */
- void override(K key, V value);
-
- /**
- * Adds a keyed object as an instantiated instance (with dependencies injected) of a class. When the value
- * type is an interface and the class to be contributed is a local file,
- * then a reloadable proxy for the value class will be created and contributed.
- *
- * @param key
- * unique id for the value
- * @param clazz
- * class to instantiate and contribute
- * @since 5.1.0.0
- */
- void addInstance(K key, Class<? extends V> clazz);
-
- /**
- * Overrides an existing contribution with a new instance. When the value
- * type is an interface and the class to be contributed is a local file,
- * then a reloadable proxy for the value class will be created and contributed.
- *
- * @param key
- * unique id of value to override
- * @param clazz
- * class to instantiate as override
- */
- void overrideInstance(K key, Class<? extends V> clazz);
-}