http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/3d4de7e1/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java deleted file mode 100644 index 701420f..0000000 --- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java +++ /dev/null @@ -1,1563 +0,0 @@ -// Copyright 2007-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.internal.services; - -import org.antlr.runtime.ANTLRInputStream; -import org.antlr.runtime.CommonTokenStream; -import org.antlr.runtime.tree.Tree; -import org.apache.tapestry5.PropertyConduit; -import org.apache.tapestry5.PropertyConduit2; -import org.apache.tapestry5.internal.InternalPropertyConduit; -import org.apache.tapestry5.internal.antlr.PropertyExpressionLexer; -import org.apache.tapestry5.internal.antlr.PropertyExpressionParser; -import org.apache.tapestry5.internal.util.IntegerRange; -import org.apache.tapestry5.internal.util.MultiKey; -import org.apache.tapestry5.ioc.AnnotationProvider; -import org.apache.tapestry5.ioc.annotations.PostInjection; -import org.apache.tapestry5.ioc.internal.NullAnnotationProvider; -import org.apache.tapestry5.ioc.internal.util.CollectionFactory; -import org.apache.tapestry5.ioc.internal.util.GenericsUtils; -import org.apache.tapestry5.ioc.internal.util.InternalUtils; -import org.apache.tapestry5.ioc.services.*; -import org.apache.tapestry5.ioc.util.AvailableValues; -import org.apache.tapestry5.ioc.util.ExceptionUtils; -import org.apache.tapestry5.ioc.util.UnknownValueException; -import org.apache.tapestry5.plastic.*; -import org.apache.tapestry5.services.ComponentClasses; -import org.apache.tapestry5.services.ComponentLayer; -import org.apache.tapestry5.services.InvalidationEventHub; -import org.apache.tapestry5.services.PropertyConduitSource; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.lang.annotation.Annotation; -import java.lang.reflect.*; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.*; - -public class PropertyConduitSourceImpl implements PropertyConduitSource -{ - static class ConduitMethods - { - private static final MethodDescription GET = getMethodDescription(PropertyConduit.class, "get", Object.class); - - private static final MethodDescription SET = getMethodDescription(PropertyConduit.class, "set", Object.class, - Object.class); - - private static final MethodDescription GET_PROPERTY_TYPE = getMethodDescription(PropertyConduit.class, - "getPropertyType"); - - private static final MethodDescription GET_PROPERTY_GENERIC_TYPE = getMethodDescription(PropertyConduit2.class, - "getPropertyGenericType"); - - private static final MethodDescription GET_PROPERTY_NAME = getMethodDescription(InternalPropertyConduit.class, - "getPropertyName"); - - private static final MethodDescription GET_ANNOTATION = getMethodDescription(AnnotationProvider.class, - "getAnnotation", Class.class); - - } - - static class DelegateMethods - { - static final Method INVERT = getMethod(PropertyConduitDelegate.class, "invert", Object.class); - - static final Method RANGE = getMethod(PropertyConduitDelegate.class, "range", int.class, int.class); - - static final Method COERCE = getMethod(PropertyConduitDelegate.class, "coerce", Object.class, Class.class); - } - - static class ArrayListMethods - { - static final Method ADD = getMethod(ArrayList.class, "add", Object.class); - } - - static class HashMapMethods - { - static final Method PUT = getMethod(HashMap.class, "put", Object.class, Object.class); - } - - private static InstructionBuilderCallback RETURN_NULL = new InstructionBuilderCallback() - { - public void doBuild(InstructionBuilder builder) - { - builder.loadNull().returnResult(); - } - }; - - private static final String[] SINGLE_OBJECT_ARGUMENT = new String[] - {Object.class.getName()}; - - @SuppressWarnings("unchecked") - private static Method getMethod(Class containingClass, String name, Class... parameterTypes) - { - try - { - return containingClass.getMethod(name, parameterTypes); - } catch (NoSuchMethodException ex) - { - throw new IllegalArgumentException(ex); - } - } - - private static MethodDescription getMethodDescription(Class containingClass, String name, Class... parameterTypes) - { - return new MethodDescription(getMethod(containingClass, name, parameterTypes)); - } - - private final AnnotationProvider nullAnnotationProvider = new NullAnnotationProvider(); - - /** - * How are null values in intermdiate terms to be handled? - */ - private enum NullHandling - { - /** - * Add code to check for null and throw exception if null. - */ - FORBID, - - /** - * Add code to check for null and short-circuit (i.e., the "?." - * safe-dereference operator) - */ - ALLOW - } - - /** - * One term in an expression. Expressions start with some root type and each term advances - * to a new type. - */ - private class Term - { - /** - * The generic type of the term. - */ - final Type type; - - final Class genericType; - - /** - * Describes the term, for use in error messages. - */ - final String description; - - final AnnotationProvider annotationProvider; - - /** - * Callback that will implement the term. - */ - final InstructionBuilderCallback callback; - - Term(Type type, Class genericType, String description, AnnotationProvider annotationProvider, - InstructionBuilderCallback callback) - { - this.type = type; - this.genericType = genericType; - this.description = description; - this.annotationProvider = annotationProvider; - this.callback = callback; - } - - Term(Type type, String description, AnnotationProvider annotationProvider, InstructionBuilderCallback callback) - { - this(type, GenericsUtils.asClass(type), description, annotationProvider, callback); - } - - Term(Type type, String description, InstructionBuilderCallback callback) - { - this(type, description, null, callback); - } - - /** - * Returns a clone of this Term with a new callback. - */ - Term withCallback(InstructionBuilderCallback newCallback) - { - return new Term(type, genericType, description, annotationProvider, newCallback); - } - } - - private final PropertyAccess access; - - private final PlasticProxyFactory proxyFactory; - - private final TypeCoercer typeCoercer; - - private final StringInterner interner; - - /** - * Keyed on combination of root class and expression. - */ - private final Map<MultiKey, PropertyConduit> cache = CollectionFactory.newConcurrentMap(); - - private final Invariant invariantAnnotation = new Invariant() - { - public Class<? extends Annotation> annotationType() - { - return Invariant.class; - } - }; - - private final AnnotationProvider invariantAnnotationProvider = new AnnotationProvider() - { - public <T extends Annotation> T getAnnotation(Class<T> annotationClass) - { - if (annotationClass == Invariant.class) - return annotationClass.cast(invariantAnnotation); - - return null; - } - }; - - private final PropertyConduit literalTrue; - - private final PropertyConduit literalFalse; - - private final PropertyConduit literalNull; - - private final PropertyConduitDelegate sharedDelegate; - - /** - * Encapsulates the process of building a PropertyConduit instance from an - * expression, as an {@link PlasticClassTransformer}. - */ - class PropertyConduitBuilder implements PlasticClassTransformer - { - private final Class rootType; - - private final String expression; - - private final Tree tree; - - private Class conduitPropertyType; - - private Type conduitPropertyGenericType; - - private String conduitPropertyName; - - private AnnotationProvider annotationProvider = nullAnnotationProvider; - - private PlasticField delegateField; - - private PlasticClass plasticClass; - - private PlasticMethod getRootMethod, navMethod; - - PropertyConduitBuilder(Class rootType, String expression, Tree tree) - { - this.rootType = rootType; - this.expression = expression; - this.tree = tree; - } - - public void transform(PlasticClass plasticClass) - { - this.plasticClass = plasticClass; - - // Create the various methods; also determine the conduit's property type, property name and identify - // the annotation provider. - - implementNavMethodAndAccessors(); - - implementOtherMethods(); - - plasticClass.addToString(String.format("PropertyConduit[%s %s]", rootType.getName(), expression)); - } - - private void implementOtherMethods() - { - PlasticField annotationProviderField = plasticClass.introduceField(AnnotationProvider.class, - "annotationProvider").inject(annotationProvider); - - plasticClass.introduceMethod(ConduitMethods.GET_ANNOTATION).delegateTo(annotationProviderField); - - plasticClass.introduceMethod(ConduitMethods.GET_PROPERTY_NAME, new InstructionBuilderCallback() - { - public void doBuild(InstructionBuilder builder) - { - builder.loadConstant(conduitPropertyName).returnResult(); - } - }); - - final PlasticField propertyTypeField = plasticClass.introduceField(Class.class, "propertyType").inject( - conduitPropertyType); - - plasticClass.introduceMethod(ConduitMethods.GET_PROPERTY_TYPE, new InstructionBuilderCallback() - { - public void doBuild(InstructionBuilder builder) - { - builder.loadThis().getField(propertyTypeField).returnResult(); - } - }); - - final PlasticField propertyGenericTypeField = plasticClass.introduceField(Type.class, "propertyGenericType").inject( - conduitPropertyGenericType); - - plasticClass.introduceMethod(ConduitMethods.GET_PROPERTY_GENERIC_TYPE, new InstructionBuilderCallback() - { - public void doBuild(InstructionBuilder builder) - { - builder.loadThis().getField(propertyGenericTypeField).returnResult(); - } - }); - } - - /** - * Creates a method that does a conversion from Object to the expected root type, with - * a null check. - */ - private void implementGetRoot() - { - getRootMethod = plasticClass.introducePrivateMethod(PlasticUtils.toTypeName(rootType), "getRoot", - SINGLE_OBJECT_ARGUMENT, null); - - getRootMethod.changeImplementation(new InstructionBuilderCallback() - { - public void doBuild(InstructionBuilder builder) - { - builder.loadArgument(0).dupe().when(Condition.NULL, new InstructionBuilderCallback() - { - public void doBuild(InstructionBuilder builder) - { - builder.throwException(NullPointerException.class, - String.format("Root object of property expression '%s' is null.", expression)); - } - }); - - builder.checkcast(rootType).returnResult(); - } - }); - } - - private boolean isLeaf(Tree node) - { - int type = node.getType(); - - return type != DEREF && type != SAFEDEREF; - } - - private void implementNavMethodAndAccessors() - { - implementGetRoot(); - - // First, create the navigate method. - - final List<InstructionBuilderCallback> callbacks = CollectionFactory.newList(); - - Type activeType = rootType; - - Tree node = tree; - - while (!isLeaf(node)) - { - Term term = analyzeDerefNode(activeType, node); - - callbacks.add(term.callback); - - activeType = term.type; - - // Second term is the continuation, possibly another chained - // DEREF, etc. - node = node.getChild(1); - } - - Class activeClass = GenericsUtils.asClass(activeType); - - if (callbacks.isEmpty()) - { - navMethod = getRootMethod; - } else - { - navMethod = plasticClass.introducePrivateMethod(PlasticUtils.toTypeName(activeClass), "navigate", - SINGLE_OBJECT_ARGUMENT, null); - - navMethod.changeImplementation(new InstructionBuilderCallback() - { - public void doBuild(InstructionBuilder builder) - { - builder.loadThis().loadArgument(0).invokeVirtual(getRootMethod); - - for (InstructionBuilderCallback callback : callbacks) - { - callback.doBuild(builder); - } - - builder.returnResult(); - } - }); - } - - implementAccessors(activeType, node); - } - - private void implementAccessors(Type activeType, Tree node) - { - switch (node.getType()) - { - case IDENTIFIER: - - implementPropertyAccessors(activeType, node); - - return; - - case INVOKE: - - // So, at this point, we have the navigation method written - // and it covers all but the terminal - // de-reference. node is an IDENTIFIER or INVOKE. We're - // ready to use the navigation - // method to implement get() and set(). - - implementMethodAccessors(activeType, node); - - return; - - case RANGEOP: - - // As currently implemented, RANGEOP can only appear as the - // top level, which - // means we didn't need the navigate method after all. - - implementRangeOpGetter(node); - implementNoOpSetter(); - - conduitPropertyType = IntegerRange.class; - conduitPropertyGenericType = IntegerRange.class; - - return; - - case LIST: - - implementListGetter(node); - implementNoOpSetter(); - - conduitPropertyType = List.class; - conduitPropertyGenericType = List.class; - - return; - - case MAP: - implementMapGetter(node); - implementNoOpSetter(); - - conduitPropertyType = Map.class; - conduitPropertyGenericType = Map.class; - - return; - - - case NOT: - implementNotOpGetter(node); - implementNoOpSetter(); - - conduitPropertyType = boolean.class; - conduitPropertyGenericType = boolean.class; - - return; - - default: - throw unexpectedNodeType(node, IDENTIFIER, INVOKE, RANGEOP, LIST, NOT); - } - } - - public void implementMethodAccessors(final Type activeType, final Tree invokeNode) - { - final Term term = buildInvokeTerm(activeType, invokeNode); - - implementNoOpSetter(); - - conduitPropertyName = term.description; - conduitPropertyType = term.genericType; - conduitPropertyGenericType = term.genericType; - annotationProvider = term.annotationProvider; - - plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback() - { - public void doBuild(InstructionBuilder builder) - { - invokeNavigateMethod(builder); - - term.callback.doBuild(builder); - - boxIfPrimitive(builder, conduitPropertyType); - - builder.returnResult(); - } - }); - - implementNoOpSetter(); - } - - public void implementPropertyAccessors(Type activeType, Tree identifierNode) - { - String propertyName = identifierNode.getText(); - - PropertyAdapter adapter = findPropertyAdapter(activeType, propertyName); - - conduitPropertyName = propertyName; - conduitPropertyType = adapter.getType(); - conduitPropertyGenericType = getGenericType(adapter); - annotationProvider = adapter; - - implementGetter(adapter); - implementSetter(adapter); - } - - private Type getGenericType(PropertyAdapter adapter) - { - Type genericType = null; - if (adapter.getField() != null) - { - genericType = adapter.getField().getGenericType(); - } - else if (adapter.getReadMethod() != null) - { - genericType = adapter.getReadMethod().getGenericReturnType(); - } - else if (adapter.getWriteMethod() != null) - { - genericType = adapter.getWriteMethod().getGenericParameterTypes()[0]; - } - else - { - throw new RuntimeException("Could not find accessor for property " + adapter.getName()); - } - - return genericType == null ? adapter.getType() : genericType; - } - - private void implementSetter(PropertyAdapter adapter) - { - if (adapter.getWriteMethod() != null) - { - implementSetter(adapter.getWriteMethod()); - return; - } - - if (adapter.getField() != null && adapter.isUpdate()) - { - implementSetter(adapter.getField()); - return; - } - - implementNoOpMethod(ConduitMethods.SET, "Expression '%s' for class %s is read-only.", expression, - rootType.getName()); - } - - private boolean isStatic(Member member) - { - return Modifier.isStatic(member.getModifiers()); - } - - private void implementSetter(final Field field) - { - if (isStatic(field)) - { - plasticClass.introduceMethod(ConduitMethods.SET, new InstructionBuilderCallback() - { - public void doBuild(InstructionBuilder builder) - { - builder.loadArgument(1).castOrUnbox(PlasticUtils.toTypeName(field.getType())); - - builder.putStaticField(field.getDeclaringClass().getName(), field.getName(), field.getType()); - - builder.returnResult(); - } - }); - - return; - } - - plasticClass.introduceMethod(ConduitMethods.SET, new InstructionBuilderCallback() - { - public void doBuild(InstructionBuilder builder) - { - invokeNavigateMethod(builder); - - builder.loadArgument(1).castOrUnbox(PlasticUtils.toTypeName(field.getType())); - - builder.putField(field.getDeclaringClass().getName(), field.getName(), field.getType()); - - builder.returnResult(); - } - }); - } - - private void implementSetter(final Method writeMethod) - { - plasticClass.introduceMethod(ConduitMethods.SET, new InstructionBuilderCallback() - { - public void doBuild(InstructionBuilder builder) - { - invokeNavigateMethod(builder); - - Class propertyType = writeMethod.getParameterTypes()[0]; - String propertyTypeName = PlasticUtils.toTypeName(propertyType); - - builder.loadArgument(1).castOrUnbox(propertyTypeName); - - builder.invoke(writeMethod); - - builder.returnResult(); - } - }); - } - - private void implementGetter(PropertyAdapter adapter) - { - if (adapter.getReadMethod() != null) - { - implementGetter(adapter.getReadMethod()); - return; - } - - if (adapter.getField() != null) - { - implementGetter(adapter.getField()); - return; - } - - implementNoOpMethod(ConduitMethods.GET, "Expression '%s' for class %s is write-only.", expression, - rootType.getName()); - } - - private void implementGetter(final Field field) - { - if (isStatic(field)) - { - plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback() - { - public void doBuild(InstructionBuilder builder) - { - builder.getStaticField(field.getDeclaringClass().getName(), field.getName(), field.getType()); - - // Cast not necessary here since the return type of get() is Object - - boxIfPrimitive(builder, field.getType()); - - builder.returnResult(); - } - }); - - return; - } - - plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback() - { - public void doBuild(InstructionBuilder builder) - { - invokeNavigateMethod(builder); - - builder.getField(field.getDeclaringClass().getName(), field.getName(), field.getType()); - - // Cast not necessary here since the return type of get() is Object - - boxIfPrimitive(builder, field.getType()); - - builder.returnResult(); - } - }); - } - - private void implementGetter(final Method readMethod) - { - plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback() - { - public void doBuild(InstructionBuilder builder) - { - invokeNavigateMethod(builder); - - invokeMethod(builder, readMethod, null, 0); - - boxIfPrimitive(builder, conduitPropertyType); - - builder.returnResult(); - } - }); - } - - private void implementRangeOpGetter(final Tree rangeNode) - { - plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback() - { - public void doBuild(InstructionBuilder builder) - { - // Put the delegate on top of the stack - - builder.loadThis().getField(getDelegateField()); - - invokeMethod(builder, DelegateMethods.RANGE, rangeNode, 0); - - builder.returnResult(); - } - }); - } - - /** - * @param node - * subexpression to invert - */ - private void implementNotOpGetter(final Tree node) - { - // Implement get() as navigate, then do a method invocation based on node - // then, then pass (wrapped) result to delegate.invert() - - plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback() - { - public void doBuild(InstructionBuilder builder) - { - Type expressionType = implementNotExpression(builder, node); - - // Yes, we know this will always be the case, for now. - - boxIfPrimitive(builder, expressionType); - - builder.returnResult(); - } - }); - } - - /** - * The first part of any implementation of get() or set(): invoke the navigation method - * and if the result is null, return immediately. - */ - private void invokeNavigateMethod(InstructionBuilder builder) - { - builder.loadThis().loadArgument(0).invokeVirtual(navMethod); - - builder.dupe().when(Condition.NULL, RETURN_NULL); - } - - /** - * Uses the builder to add instructions for a subexpression. - * - * @param builder - * used to add instructions - * @param activeType - * type of value on top of the stack when this code will execute, or null if no value on stack - * @param node - * defines the expression - * @return the expression type - */ - private Type implementSubexpression(InstructionBuilder builder, Type activeType, Tree node) - { - Term term; - - while (true) - { - switch (node.getType()) - { - case IDENTIFIER: - case INVOKE: - - if (activeType == null) - { - invokeGetRootMethod(builder); - - activeType = rootType; - } - - term = buildTerm(activeType, node); - - term.callback.doBuild(builder); - - return term.type; - - case INTEGER: - - builder.loadConstant(new Long(node.getText())); - - return long.class; - - case DECIMAL: - - builder.loadConstant(new Double(node.getText())); - - return double.class; - - case STRING: - - builder.loadConstant(node.getText()); - - return String.class; - - case DEREF: - case SAFEDEREF: - - if (activeType == null) - { - invokeGetRootMethod(builder); - - activeType = rootType; - } - - term = analyzeDerefNode(activeType, node); - - term.callback.doBuild(builder); - - activeType = GenericsUtils.asClass(term.type); - - node = node.getChild(1); - - break; - - case TRUE: - case FALSE: - - builder.loadConstant(node.getType() == TRUE ? 1 : 0); - - return boolean.class; - - case LIST: - - return implementListConstructor(builder, node); - - case MAP: - return implementMapConstructor(builder, node); - - case NOT: - - return implementNotExpression(builder, node); - - case THIS: - - invokeGetRootMethod(builder); - - return rootType; - - case NULL: - - builder.loadNull(); - - return Void.class; - - default: - throw unexpectedNodeType(node, TRUE, FALSE, INTEGER, DECIMAL, STRING, DEREF, SAFEDEREF, - IDENTIFIER, INVOKE, LIST, NOT, THIS, NULL); - } - } - } - - public void invokeGetRootMethod(InstructionBuilder builder) - { - builder.loadThis().loadArgument(0).invokeVirtual(getRootMethod); - } - - private void implementListGetter(final Tree listNode) - { - plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback() - { - public void doBuild(InstructionBuilder builder) - { - implementListConstructor(builder, listNode); - - builder.returnResult(); - } - }); - } - - private Type implementListConstructor(InstructionBuilder builder, Tree listNode) - { - // First, create an empty instance of ArrayList - - int count = listNode.getChildCount(); - - builder.newInstance(ArrayList.class); - builder.dupe().loadConstant(count).invokeConstructor(ArrayList.class, int.class); - - for (int i = 0; i < count; i++) - { - builder.dupe(); // the ArrayList - - Type expressionType = implementSubexpression(builder, null, listNode.getChild(i)); - - boxIfPrimitive(builder, GenericsUtils.asClass(expressionType)); - - // Add the value to the array, then pop off the returned boolean - builder.invoke(ArrayListMethods.ADD).pop(); - } - - return ArrayList.class; - } - - private void implementMapGetter(final Tree mapNode) - { - plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback() - { - public void doBuild(InstructionBuilder builder) - { - implementMapConstructor(builder, mapNode); - - builder.returnResult(); - } - }); - } - - private Type implementMapConstructor(InstructionBuilder builder, Tree mapNode) - { - int count = mapNode.getChildCount(); - builder.newInstance(HashMap.class); - builder.dupe().loadConstant(count).invokeConstructor(HashMap.class, int.class); - - for (int i = 0; i < count; i += 2) - { - builder.dupe(); - - //build the key: - Type keyType = implementSubexpression(builder, null, mapNode.getChild(i)); - boxIfPrimitive(builder, GenericsUtils.asClass(keyType)); - - //and the value: - Type valueType = implementSubexpression(builder, null, mapNode.getChild(i + 1)); - boxIfPrimitive(builder, GenericsUtils.asClass(valueType)); - - //put the value into the array, then pop off the returned object. - builder.invoke(HashMapMethods.PUT).pop(); - - } - - return HashMap.class; - } - - - private void implementNoOpSetter() - { - implementNoOpMethod(ConduitMethods.SET, "Expression '%s' for class %s is read-only.", expression, - rootType.getName()); - } - - public void implementNoOpMethod(MethodDescription method, String format, Object... arguments) - { - final String message = String.format(format, arguments); - - plasticClass.introduceMethod(method).changeImplementation(new InstructionBuilderCallback() - { - public void doBuild(InstructionBuilder builder) - { - builder.throwException(RuntimeException.class, message); - } - }); - } - - /** - * Invokes a method that may take parameters. The children of the invokeNode are subexpressions - * to be evaluated, and potentially coerced, so that they may be passed to the method. - * - * @param builder - * constructs code - * @param method - * method to invoke - * @param node - * INVOKE or RANGEOP node - * @param childOffset - * offset within the node to the first child expression (1 in an INVOKE node because the - * first child is the method name, 0 in a RANGEOP node) - */ - private void invokeMethod(InstructionBuilder builder, Method method, Tree node, int childOffset) - { - // We start with the target object for the method on top of the stack. - // Next, we have to push each method parameter, which may include boxing/deboxing - // and coercion. Once the code is in good shape, there's a lot of room to optimize - // the bytecode (a bit too much boxing/deboxing occurs, as well as some unnecessary - // trips through TypeCoercer). We might also want to have a local variable to store - // the root object (result of getRoot()). - - Class[] parameterTypes = method.getParameterTypes(); - - for (int i = 0; i < parameterTypes.length; i++) - { - Type expressionType = implementSubexpression(builder, null, node.getChild(i + childOffset)); - - // The value left on the stack is not primitive, and expressionType represents - // its real type. - - Class parameterType = parameterTypes[i]; - - if (!parameterType.isAssignableFrom(GenericsUtils.asClass(expressionType))) - { - boxIfPrimitive(builder, expressionType); - - builder.loadThis().getField(getDelegateField()); - builder.swap().loadTypeConstant(PlasticUtils.toWrapperType(parameterType)); - builder.invoke(DelegateMethods.COERCE); - - if (parameterType.isPrimitive()) - { - builder.castOrUnbox(parameterType.getName()); - } else - { - builder.checkcast(parameterType); - } - } - - // And that should leave an object of the correct type on the stack, - // ready for the method invocation. - } - - // Now the target object and all parameters are in place. - - builder.invoke(method.getDeclaringClass(), method.getReturnType(), method.getName(), - method.getParameterTypes()); - } - - /** - * Analyzes a DEREF or SAFEDEREF node, proving back a term that identifies its type and provides a callback to - * peform the dereference. - * - * @return a term indicating the type of the expression to this point, and a {@link InstructionBuilderCallback} - * to advance the evaluation of the expression form the previous value to the current - */ - private Term analyzeDerefNode(Type activeType, Tree node) - { - // The first child is the term. - - Tree term = node.getChild(0); - - boolean allowNull = node.getType() == SAFEDEREF; - - return buildTerm(activeType, term, allowNull ? NullHandling.ALLOW : NullHandling.FORBID); - } - - private Term buildTerm(Type activeType, Tree term, final NullHandling nullHandling) - { - assertNodeType(term, IDENTIFIER, INVOKE); - - final Term simpleTerm = buildTerm(activeType, term); - - if (simpleTerm.genericType.isPrimitive()) - return simpleTerm; - - return simpleTerm.withCallback(new InstructionBuilderCallback() - { - public void doBuild(InstructionBuilder builder) - { - simpleTerm.callback.doBuild(builder); - - builder.dupe().when(Condition.NULL, new InstructionBuilderCallback() - { - public void doBuild(InstructionBuilder builder) - { - switch (nullHandling) - { - // It is necessary to load a null onto the stack (even if there's already one - // there) because of the verifier. It sees the return when the stack contains an - // intermediate value (along the navigation chain) and thinks the method is - // returning a value of the wrong type. - - case ALLOW: - builder.loadNull().returnResult(); - - case FORBID: - - builder.loadConstant(simpleTerm.description); - builder.loadConstant(expression); - builder.loadArgument(0); - - builder.invokeStatic(PropertyConduitSourceImpl.class, NullPointerException.class, - "nullTerm", String.class, String.class, Object.class); - builder.throwException(); - - break; - - } - } - }); - } - }); - } - - private void assertNodeType(Tree node, int... expected) - { - int type = node.getType(); - - for (int e : expected) - { - if (type == e) - return; - } - - throw unexpectedNodeType(node, expected); - } - - private RuntimeException unexpectedNodeType(Tree node, int... expected) - { - List<String> tokenNames = CollectionFactory.newList(); - - for (int i = 0; i < expected.length; i++) - tokenNames.add(PropertyExpressionParser.tokenNames[expected[i]]); - - String message = String.format("Node %s was type %s, but was expected to be (one of) %s.", - node.toStringTree(), PropertyExpressionParser.tokenNames[node.getType()], - InternalUtils.joinSorted(tokenNames)); - - return new RuntimeException(message); - } - - private Term buildTerm(Type activeType, Tree termNode) - { - switch (termNode.getType()) - { - case INVOKE: - - return buildInvokeTerm(activeType, termNode); - - case IDENTIFIER: - - return buildPropertyAccessTerm(activeType, termNode); - - default: - throw unexpectedNodeType(termNode, INVOKE, IDENTIFIER); - } - } - - private Term buildPropertyAccessTerm(Type activeType, Tree termNode) - { - String propertyName = termNode.getText(); - - PropertyAdapter adapter = findPropertyAdapter(activeType, propertyName); - - // Prefer the accessor over the field - - if (adapter.getReadMethod() != null) - { - return buildGetterMethodAccessTerm(activeType, propertyName, - adapter.getReadMethod()); - } - - if (adapter.getField() != null) - { - return buildPublicFieldAccessTerm(activeType, propertyName, - adapter.getField()); - } - - throw new RuntimeException(String.format( - "Property '%s' of class %s is not readable (it has no read accessor method).", adapter.getName(), - adapter.getBeanType().getName())); - } - - public PropertyAdapter findPropertyAdapter(Type activeType, String propertyName) - { - Class activeClass = GenericsUtils.asClass(activeType); - - ClassPropertyAdapter classAdapter = access.getAdapter(activeClass); - PropertyAdapter adapter = classAdapter.getPropertyAdapter(propertyName); - - if (adapter == null) - { - final List<String> names = classAdapter.getPropertyNames(); - final String className = activeClass.getName(); - throw new UnknownValueException(String.format( - "Class %s does not contain a property (or public field) named '%s'.", className, propertyName), - new AvailableValues("Properties (and public fields)", names)); - } - return adapter; - } - - private Term buildGetterMethodAccessTerm(final Type activeType, String propertyName, final Method readMethod) - { - Type returnType = GenericsUtils.extractActualType(activeType, readMethod); - - return new Term(returnType, propertyName, new InstructionBuilderCallback() - { - public void doBuild(InstructionBuilder builder) - { - invokeMethod(builder, readMethod, null, 0); - - Type genericType = GenericsUtils.extractActualType(activeType, readMethod); - - castToGenericType(builder, readMethod.getReturnType(), genericType); - } - }); - } - - private Term buildPublicFieldAccessTerm(Type activeType, String propertyName, final Field field) - { - final Type fieldType = GenericsUtils.extractActualType(activeType, field); - - return new Term(fieldType, propertyName, new InstructionBuilderCallback() - { - public void doBuild(InstructionBuilder builder) - { - Class rawFieldType = field.getType(); - - String rawTypeName = PlasticUtils.toTypeName(rawFieldType); - String containingClassName = field.getDeclaringClass().getName(); - String fieldName = field.getName(); - - if (isStatic(field)) - { - // We've gone to the trouble of loading the root object, or navigated to some other object, - // but we don't need or want the instance, since it's a static field we're accessing. - // Ideally, we would optimize this, and only generate and invoke the getRoot() and nav() methods as needed, but - // access to public fields is relatively rare, and the cost is just the unused bytecode. - - builder.pop(); - - builder.getStaticField(containingClassName, fieldName, rawTypeName); - - } else - { - builder.getField(containingClassName, fieldName, rawTypeName); - } - - castToGenericType(builder, rawFieldType, fieldType); - } - - }); - } - - /** - * Casts the results of a field read or method invocation based on generic information. - * - * @param builder - * used to add instructions - * @param rawType - * the simple type (often Object) of the field (or method return type) - * @param genericType - * the generic Type, from which parameterizations can be determined - */ - private void castToGenericType(InstructionBuilder builder, Class rawType, final Type genericType) - { - if (!genericType.equals(rawType)) - { - Class castType = GenericsUtils.asClass(genericType); - builder.checkcast(castType); - } - } - - private Term buildInvokeTerm(final Type activeType, final Tree invokeNode) - { - String methodName = invokeNode.getChild(0).getText(); - - int parameterCount = invokeNode.getChildCount() - 1; - - Class activeClass = GenericsUtils.asClass(activeType); - - final Method method = findMethod(activeClass, methodName, parameterCount); - - if (method.getReturnType().equals(void.class)) - throw new RuntimeException(String.format("Method %s.%s() returns void.", activeClass.getName(), - methodName)); - - Type returnType = GenericsUtils.extractActualType(activeType, method); - - return new Term(returnType, toUniqueId(method), InternalUtils.toAnnotationProvider(method), new InstructionBuilderCallback() - { - public void doBuild(InstructionBuilder builder) - { - invokeMethod(builder, method, invokeNode, 1); - - Type genericType = GenericsUtils.extractActualType(activeType, method); - - castToGenericType(builder, method.getReturnType(), genericType); - } - } - ); - } - - private Method findMethod(Class activeType, String methodName, int parameterCount) - { - Class searchType = activeType; - - while (true) - { - - for (Method method : searchType.getMethods()) - { - if (method.getParameterTypes().length == parameterCount - && method.getName().equalsIgnoreCase(methodName)) - return method; - } - - // TAP5-330 - if (searchType != Object.class) - { - searchType = Object.class; - } else - { - throw new RuntimeException(String.format("Class %s does not contain a public method named '%s()'.", - activeType.getName(), methodName)); - } - } - } - - public void boxIfPrimitive(InstructionBuilder builder, Type termType) - { - boxIfPrimitive(builder, GenericsUtils.asClass(termType)); - } - - public void boxIfPrimitive(InstructionBuilder builder, Class termType) - { - if (termType.isPrimitive()) - builder.boxPrimitive(termType.getName()); - } - - public Class implementNotExpression(InstructionBuilder builder, final Tree notNode) - { - Type expressionType = implementSubexpression(builder, null, notNode.getChild(0)); - - boxIfPrimitive(builder, expressionType); - - // Now invoke the delegate invert() method - - builder.loadThis().getField(getDelegateField()); - - builder.swap().invoke(DelegateMethods.INVERT); - - return boolean.class; - } - - /** - * Defer creation of the delegate field unless actually needed. - */ - private PlasticField getDelegateField() - { - if (delegateField == null) - delegateField = plasticClass.introduceField(PropertyConduitDelegate.class, "delegate").inject( - sharedDelegate); - - return delegateField; - } - } - - public PropertyConduitSourceImpl(PropertyAccess access, @ComponentLayer - PlasticProxyFactory proxyFactory, TypeCoercer typeCoercer, StringInterner interner) - { - this.access = access; - this.proxyFactory = proxyFactory; - this.typeCoercer = typeCoercer; - this.interner = interner; - - literalTrue = createLiteralConduit(Boolean.class, true); - literalFalse = createLiteralConduit(Boolean.class, false); - literalNull = createLiteralConduit(Void.class, null); - - sharedDelegate = new PropertyConduitDelegate(typeCoercer); - } - - @PostInjection - public void listenForInvalidations(@ComponentClasses InvalidationEventHub hub) - { - hub.clearOnInvalidation(cache); - } - - - public PropertyConduit create(Class rootClass, String expression) - { - assert rootClass != null; - assert InternalUtils.isNonBlank(expression); - - MultiKey key = new MultiKey(rootClass, expression); - - PropertyConduit result = cache.get(key); - - if (result == null) - { - result = build(rootClass, expression); - cache.put(key, result); - } - - return result; - } - - /** - * Builds a subclass of {@link PropertyConduitDelegate} that implements the - * get() and set() methods and overrides the - * constructor. In a worst-case race condition, we may build two (or more) - * conduits for the same - * rootClass/expression, and it will get sorted out when the conduit is - * stored into the cache. - * - * @param rootClass - * class of root object for expression evaluation - * @param expression - * expression to be evaluated - * @return the conduit - */ - private PropertyConduit build(final Class rootClass, String expression) - { - Tree tree = parse(expression); - - try - { - switch (tree.getType()) - { - case TRUE: - - return literalTrue; - - case FALSE: - - return literalFalse; - - case NULL: - - return literalNull; - - case INTEGER: - - // Leading '+' may screw this up. - // TODO: Singleton instance for "0", maybe "1"? - - return createLiteralConduit(Long.class, new Long(tree.getText())); - - case DECIMAL: - - // Leading '+' may screw this up. - // TODO: Singleton instance for "0.0"? - - return createLiteralConduit(Double.class, new Double(tree.getText())); - - case STRING: - - return createLiteralConduit(String.class, tree.getText()); - - case RANGEOP: - - Tree fromNode = tree.getChild(0); - Tree toNode = tree.getChild(1); - - // If the range is defined as integers (not properties, etc.) - // then it is possible to calculate the value here, once, and not - // build a new class. - - if (fromNode.getType() != INTEGER || toNode.getType() != INTEGER) - break; - - int from = Integer.parseInt(fromNode.getText()); - int to = Integer.parseInt(toNode.getText()); - - IntegerRange ir = new IntegerRange(from, to); - - return createLiteralConduit(IntegerRange.class, ir); - - case THIS: - - return createLiteralThisPropertyConduit(rootClass); - - default: - break; - } - - return proxyFactory.createProxy(InternalPropertyConduit.class, - new PropertyConduitBuilder(rootClass, expression, tree)).newInstance(); - } catch (Exception ex) - { - throw new PropertyExpressionException(String.format("Exception generating conduit for expression '%s': %s", - expression, ExceptionUtils.toMessage(ex)), expression, ex); - } - } - - private PropertyConduit createLiteralThisPropertyConduit(final Class rootClass) - { - return new PropertyConduit() - { - public Object get(Object instance) - { - return instance; - } - - public void set(Object instance, Object value) - { - throw new RuntimeException("Literal values are not updateable."); - } - - public Class getPropertyType() - { - return rootClass; - } - - public Type getPropertyGenericType() - { - return rootClass; - } - - public <T extends Annotation> T getAnnotation(Class<T> annotationClass) - { - return invariantAnnotationProvider.getAnnotation(annotationClass); - } - }; - } - - private <T> PropertyConduit createLiteralConduit(Class<T> type, T value) - { - return new LiteralPropertyConduit(typeCoercer, type, invariantAnnotationProvider, interner.format( - "LiteralPropertyConduit[%s]", value), value); - } - - private Tree parse(String expression) - { - InputStream is = new ByteArrayInputStream(expression.getBytes()); - - ANTLRInputStream ais; - - try - { - ais = new ANTLRInputStream(is); - } catch (IOException ex) - { - throw new RuntimeException(ex); - } - - PropertyExpressionLexer lexer = new PropertyExpressionLexer(ais); - - CommonTokenStream tokens = new CommonTokenStream(lexer); - - PropertyExpressionParser parser = new PropertyExpressionParser(tokens); - - try - { - return (Tree) parser.start().getTree(); - } catch (Exception ex) - { - throw new RuntimeException(String.format("Error parsing property expression '%s': %s.", expression, - ex.getMessage()), ex); - } - } - - /** - * May be invoked from fabricated PropertyConduit instances. - */ - @SuppressWarnings("unused") - public static NullPointerException nullTerm(String term, String expression, Object root) - { - String message = String.format("Property '%s' (within property expression '%s', of %s) is null.", term, - expression, root); - - return new NullPointerException(message); - } - - private static String toUniqueId(Method method) - { - StringBuilder builder = new StringBuilder(method.getName()).append("("); - String sep = ""; - - for (Class parameterType : method.getParameterTypes()) - { - builder.append(sep); - builder.append(PlasticUtils.toTypeName(parameterType)); - - sep = ","; - } - - return builder.append(")").toString(); - } -}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/3d4de7e1/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/IntegerRange.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/IntegerRange.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/IntegerRange.java deleted file mode 100644 index 7b2b7ab..0000000 --- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/IntegerRange.java +++ /dev/null @@ -1,125 +0,0 @@ -// 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.internal.util; - -import java.util.Iterator; - -/** - * Represents a sequence of integer values, either ascending or descending. The sequence is always inclusive (of the - * finish value). - */ -public final class IntegerRange implements Iterable<Integer> -{ - private final int start; - - private final int finish; - - private class RangeIterator implements Iterator<Integer> - { - private final int increment; - - private int value = start; - - private boolean hasNext = true; - - RangeIterator() - { - increment = start < finish ? +1 : -1; - } - - public boolean hasNext() - { - return hasNext; - } - - public Integer next() - { - if (!hasNext) throw new IllegalStateException(); - - int result = value; - - hasNext = value != finish; - - value += increment; - - return result; - } - - public void remove() - { - throw new UnsupportedOperationException(); - } - - } - - public IntegerRange(final int start, final int finish) - { - this.start = start; - this.finish = finish; - } - - public int getFinish() - { - return finish; - } - - public int getStart() - { - return start; - } - - @Override - public String toString() - { - return String.format("%d..%d", start, finish); - } - - /** - * The main puprose of a range object is to produce an Iterator. Since IntegerRange is iterable, it is useful with - * the Tapestry Loop component, but also with the Java for loop! - */ - public Iterator<Integer> iterator() - { - return new RangeIterator(); - } - - @Override - public int hashCode() - { - final int PRIME = 31; - - int result = PRIME + finish; - - result = PRIME * result + start; - - return result; - } - - /** - * Returns true if the other object is an IntegerRange with the same start and finish values. - */ - @Override - public boolean equals(Object obj) - { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - final IntegerRange other = (IntegerRange) obj; - if (finish != other.finish) return false; - - return start == other.start; - } - -} http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/3d4de7e1/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/MultiKey.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/MultiKey.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/MultiKey.java deleted file mode 100644 index 503bb1f..0000000 --- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/MultiKey.java +++ /dev/null @@ -1,86 +0,0 @@ -// 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.internal.util; - -import java.util.Arrays; - -/** - * Combines multiple values to form a single composite key. MultiKey can often be used as an alternative to nested - * maps. - */ -public final class MultiKey -{ - private static final int PRIME = 31; - - private final Object[] values; - - private final int hashCode; - - /** - * Creates a new instance from the provided values. It is assumed that the values provided are good map keys - * themselves -- immutable, with proper implementations of equals() and hashCode(). - * - * @param values - */ - public MultiKey(Object... values) - { - this.values = values; - - hashCode = PRIME * Arrays.hashCode(this.values); - } - - @Override - public int hashCode() - { - return hashCode; - } - - @Override - public boolean equals(Object obj) - { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - final MultiKey other = (MultiKey) obj; - - return Arrays.equals(values, other.values); - } - - @Override - public String toString() - { - StringBuilder builder = new StringBuilder("MultiKey["); - - boolean first = true; - - for (Object o : values) - { - if (!first) - builder.append(", "); - - builder.append(o); - - first = false; - } - - builder.append("]"); - - return builder.toString(); - } - -} http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/3d4de7e1/tapestry-core/src/main/java/org/apache/tapestry5/services/BeanModelSource.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/BeanModelSource.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/BeanModelSource.java deleted file mode 100644 index 16b4fca..0000000 --- a/tapestry-core/src/main/java/org/apache/tapestry5/services/BeanModelSource.java +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2007, 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.services; - -import org.apache.tapestry5.beaneditor.BeanModel; -import org.apache.tapestry5.ioc.Messages; - -/** - * Used by a component to create a default {@link org.apache.tapestry5.beaneditor.BeanModel} for a particular bean - * class. Also provides support to the model by generating validation information for individual fields. - * <p/> - * BeanModels are the basis for the {@link org.apache.tapestry5.corelib.components.BeanEditor} and {@link - * org.apache.tapestry5.corelib.components.Grid} comopnents. - * - * @see org.apache.tapestry5.services.PropertyConduitSource - */ -public interface BeanModelSource -{ - /** - * Creates a new model used for editing the indicated bean class. The model will represent all read/write properties - * of the bean. The order of properties is determined from the order of the getter methods in the code, and can be - * overridden with the {@link org.apache.tapestry5.beaneditor.ReorderProperties} annotation. The labels for the - * properties are derived from the property names, but if the component's message catalog has keys of the form - * <code>propertyName-label</code>, then those will be used instead. - * <p/> - * Models are <em>mutable</em>, so they are not cached, a fresh instance is created each time. - * - * @param beanClass class of object to be edited - * @param filterReadOnlyProperties if true, then properties that are read-only will be skipped (leaving only - * read-write properties, appropriate for {@link org.apache.tapestry5.corelib.components.BeanEditForm}, - * etc.). If false, then both read-only and read-write properties will be included - * (appropriate for {@link org.apache.tapestry5.corelib.components.Grid} or {@link - * org.apache.tapestry5.corelib.components.BeanDisplay}). - * @param messages Used to find explicit overrides of - * @return a model - * @deprecated use {@link #createDisplayModel(Class, org.apache.tapestry5.ioc.Messages)} or {@link - * #createEditModel(Class, org.apache.tapestry5.ioc.Messages)} - */ - <T> BeanModel<T> create(Class<T> beanClass, boolean filterReadOnlyProperties, Messages messages); - - /** - * Creates a model for display purposes; this may include properties which are read-only. - * - * @param beanClass class of object to be edited - * @param messages - * @return a model containing properties that can be presented to the user - */ - <T> BeanModel<T> createDisplayModel(Class<T> beanClass, Messages messages); - - /** - * Creates a model for edit and update purposes, only properties that are fully read-write are included. - * - * @param beanClass class of object to be edited - * @param messages - * @return a model containing properties that can be presented to the user - */ - <T> BeanModel<T> createEditModel(Class<T> beanClass, Messages messages); -} http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/3d4de7e1/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentClasses.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentClasses.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentClasses.java deleted file mode 100644 index c901d3a..0000000 --- a/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentClasses.java +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2008, 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.services; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Marker annotation used to inject the correct {@link org.apache.tapestry5.services.InvalidationEventHub} service - * responsible for invalidations when underlying component class files are changed. - * - * @since 5.1.0.0 - */ -@Target( -{ ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD }) -@Retention(RetentionPolicy.RUNTIME) -@Documented -public @interface ComponentClasses -{ -} http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/3d4de7e1/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentLayer.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentLayer.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentLayer.java deleted file mode 100644 index e342c3f..0000000 --- a/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentLayer.java +++ /dev/null @@ -1,37 +0,0 @@ -// 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.services; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * Marker annotation used to identify a service from the component layer that conflicts, in terms of service interface, - * with a service from elsewhere. In particular, this is used to disambiguate {@link org.apache.tapestry5.ioc.services.PlasticProxyFactory} which has one implementation (marked with {@link - * org.apache.tapestry5.ioc.services.Builtin} and another with this annotation. - */ -@Target( - {PARAMETER, FIELD}) -@Retention(RUNTIME) -@Documented -public @interface ComponentLayer -{ - -} http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/3d4de7e1/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationEventHub.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationEventHub.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationEventHub.java deleted file mode 100644 index 77b028e..0000000 --- a/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationEventHub.java +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2006, 2007, 2008, 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.services; - -import java.util.Map; - -/** - * An object which manages a list of {@link org.apache.tapestry5.services.InvalidationListener}s. There are multiple - * event hub services implementing this interface, each with a specific marker annotation; each can register listeners - * and fire events; these are based on the type of resource that has been invalidated. Tapestry has built-in support - * for: - * <dl> - * <dt>message catalog resources - * <dd>{@link org.apache.tapestry5.services.ComponentMessages} marker annotation - * <dt>component templates - * <dd>{@link org.apache.tapestry5.services.ComponentTemplates} marker annotation - * <dt>component classes - * <dd>{@link org.apache.tapestry5.services.ComponentClasses} marker annotation - * </dl> - * <p/> - * Starting in Tapestry 5.3, these services are disabled in production (it does nothing). - * - * @since 5.1.0.0 - */ -public interface InvalidationEventHub -{ - /** - * Adds a listener, who needs to know when an underlying resource of a given category has changed (so that the - * receiver may discard any cached data that may have been invalidated). Does nothing in production mode. - * - * @deprecated in 5.4, use {@link #addInvalidationCallback(Runnable)} instead} - */ - void addInvalidationListener(InvalidationListener listener); - - /** - * Adds a callback that is invoked when an underlying tracked resource has changed. Does nothing in production mode. - * - * @since 5.4 - */ - void addInvalidationCallback(Runnable callback); - - /** - * Adds a callback that clears the map. - * - * @since 5.4 - */ - void clearOnInvalidation(Map<?,?> map); -} http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/3d4de7e1/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationListener.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationListener.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationListener.java deleted file mode 100644 index b9b4aa3..0000000 --- a/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationListener.java +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2006, 2007, 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.services; - -/** - * Interface for objects that may cache information that can be invalidated. Invalidation occurs when external files, - * from which in-memory data is cached, is determined to have changed. Granularity is very limited; when any external - * file is found to have changed, the event is fired (with the expectation that the cleared cache will be repopulated as - * necessary). - * - * @see org.apache.tapestry5.services.InvalidationEventHub - * @since 5.1.0.0 - * @deprecated In 5.4; use {@link InvalidationEventHub#addInvalidationCallback(Runnable)} instead - */ -public interface InvalidationListener -{ - /** - * Invoked to indicate that some object is invalid. The receiver should clear its cache. - */ - void objectWasInvalidated(); -} http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/3d4de7e1/tapestry-core/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java deleted file mode 100644 index 312cd60..0000000 --- a/tapestry-core/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2007, 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.services; - -import org.apache.tapestry5.PropertyConduit; - -/** - * A source for {@link org.apache.tapestry5.PropertyConduit}s, which can be thought of as a compiled property path - * expression. PropertyConduits are the basis of the "prop:" binding factory, thus this service defines the expression - * format used by the {@link org.apache.tapestry5.internal.bindings.PropBindingFactory}. - */ -public interface PropertyConduitSource -{ - /** - * Returns a property conduit instance for the given expression. PropertyConduitSource caches the conduits it - * returns, so despite the name, this method does not always create a <em>new</em> conduit. The cache is cleared if - * a change to component classes is observed. - * <p/> - * Callers of this method should observe notifications from the {@link org.apache.tapestry5.services.InvalidationEventHub} - * for {@link org.apache.tapestry5.services.ComponentClasses} and discard any aquired conduits; failure to do so - * will create memory leaks whenever component classes change (the conduits will keep references to the old classes - * and classloaders). - * - * @param rootType the type of the root object to which the expression is applied - * @param expression expression to be evaluated on instances of the root class - * @return RuntimeException if the expression is invalid (poorly formed, references non-existent properties, etc.) - */ - PropertyConduit create(Class rootType, String expression); -} http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/3d4de7e1/tapestry-ioc/build.gradle ---------------------------------------------------------------------- diff --git a/tapestry-ioc/build.gradle b/tapestry-ioc/build.gradle index e890f7e..5a5321f 100644 --- a/tapestry-ioc/build.gradle +++ b/tapestry-ioc/build.gradle @@ -4,6 +4,7 @@ dependencies { compile project(':tapestry-func') compile project(':tapestry5-annotations') compile project(":plastic") + compile project(":beanmodel") provided project(':tapestry-test') http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/3d4de7e1/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/AnnotationProvider.java ---------------------------------------------------------------------- diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/AnnotationProvider.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/AnnotationProvider.java deleted file mode 100644 index 1f0e744..0000000 --- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/AnnotationProvider.java +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2007, 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; - -import java.lang.annotation.Annotation; - -/** - * A source of annotations. This interface is used to mask where the annotations come from (for example, from a Method, - * a Class, or some other source). - */ -public interface AnnotationProvider -{ - /** - * Searches for the specified annotation, returning the matching annotation instance. - * - * @param <T> - * @param annotationClass used to select the annotation to return - * @return the annotation, or null if not found - */ - <T extends Annotation> T getAnnotation(Class<T> annotationClass); -} http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/3d4de7e1/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Locatable.java ---------------------------------------------------------------------- diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Locatable.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Locatable.java deleted file mode 100644 index 37b6551..0000000 --- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Locatable.java +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2006, 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; - -/** - * Interface implemented by objects which carry a location tag. Defines a readable property, location. - */ -@SuppressWarnings({"JavaDoc"}) -public interface Locatable -{ - /** - * Returns the location associated with this object for error reporting purposes. - */ - Location getLocation(); -} http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/3d4de7e1/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Location.java ---------------------------------------------------------------------- diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Location.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Location.java deleted file mode 100644 index e6688c2..0000000 --- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Location.java +++ /dev/null @@ -1,38 +0,0 @@ -// 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; - -/** - * A kind of tag applied to other objects to identify where they came from, in terms of a file (the resource), a line - * number, and a column number. This is part of "line precise exception reporting", whereby errors at runtime can be - * tracked backwards to the files from which they were parsed or otherwise constructed. - */ -public interface Location -{ - /** - * The resource from which the object tagged with a location was derived. - */ - Resource getResource(); - - /** - * The line number within the resource, if known, or -1 otherwise. - */ - int getLine(); - - /** - * The column number within the line if known, or -1 otherwise. - */ - int getColumn(); -} http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/3d4de7e1/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MessageFormatter.java ---------------------------------------------------------------------- diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MessageFormatter.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MessageFormatter.java deleted file mode 100644 index e90eb65..0000000 --- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MessageFormatter.java +++ /dev/null @@ -1,32 +0,0 @@ -// 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; - -/** - * Obtained from a {@link org.apache.tapestry5.ioc.Messages}, used to format messages for a specific localized message - * key. - */ -public interface MessageFormatter -{ - /** - * Formats the message. The arguments are passed to {@link java.util.Formatter} as is with one exception: Object of - * type {@link Throwable} are converted to their {@link Throwable#getMessage()} (or, if that is null, to the name of - * the class). - * - * @param args - * @return formatted string - */ - String format(Object... args); -} http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/3d4de7e1/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Messages.java ---------------------------------------------------------------------- diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Messages.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Messages.java deleted file mode 100644 index ba7452c..0000000 --- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Messages.java +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2006, 2007, 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; - -import java.util.Set; - -/** - * Provides access to a messages catalog, a set of properties files that provide localized messages for a particular - * locale. The message catalog consists of keys and values and follows the semantics of a Java {@link - * java.util.ResourceBundle} with some changes. - */ -public interface Messages -{ - /** - * Returns true if the bundle contains the named key. - */ - boolean contains(String key); - - /** - * Returns the localized message for the given key. If catalog does not contain such a key, then a modified version - * of the key is returned (converted to upper case and enclosed in brackets). - * - * @param key - * @return localized message for key, or placeholder - */ - String get(String key); - - /** - * Returns a formatter for the message, which can be used to substitute arguments (as per {@link - * java.util.Formatter}). - * - * @param key - * @return formattable object - */ - MessageFormatter getFormatter(String key); - - /** - * Convenience for accessing a formatter and formatting a localized message with arguments. - */ - String format(String key, Object... args); - - /** - * Returns a set of all the keys for which this instance may provide a value. - * - * @return set of keys - * @since 5.4 - */ - Set<String> getKeys(); -}
