    001    // Copyright 2006, 2007, 2008, 2010, 2011 The Apache Software Foundation
    002    //
    003    // Licensed under the Apache License, Version 2.0 (the "License");
    004    // you may not use this file except in compliance with the License.
    005    // You may obtain a copy of the License at
    006    //
    007    // http://www.apache.org/licenses/LICENSE-2.0
    008    //
    009    // Unless required by applicable law or agreed to in writing, software
    010    // distributed under the License is distributed on an "AS IS" BASIS,
    011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    012    // See the License for the specific language governing permissions and
    013    // limitations under the License.
    014
    015    package org.apache.tapestry5.services;
    016
    017    import java.lang.annotation.Annotation;
    018    import java.util.List;
    019
    020    import org.apache.tapestry5.ComponentResources;
    021    import org.apache.tapestry5.func.Predicate;
    022    import org.apache.tapestry5.ioc.AnnotationProvider;
    023    import org.apache.tapestry5.model.MutableComponentModel;
    024    import org.apache.tapestry5.plastic.PlasticClass;
    025    import org.apache.tapestry5.runtime.Component;
    026    import org.apache.tapestry5.runtime.Event;
    027    import org.slf4j.Logger;
    028
    029    /**
    030     * Contains class-specific information used when transforming a raw component class into an
    031     * executable component class.
    032     * An executable class is one that has been transformed to work within Tapestry. This includes
    033     * adding interfaces
    034     * ({@link org.apache.tapestry5.runtime.Component}) but also transforming access to fields, based on
    035     * annotations and
    036     * naming conventions. Most of the changes are provided by different implementations of
    037     * {@link ComponentClassTransformWorker}.
    038     * <p/>
    039     * Much of this information is somewhat like ordinary reflection, but applies to a class that has not yet been loaded.
    040     * Field types, return types, parameter types and exception types are represented as string names, since any of them may
    041     * be a class that has not yet been loaded and transformed as well.
    042     * <p/>
    043     * Transformation is primarily about identifying annotations on fields and on methods and changing the class, adding new
    044     * interfaces, fields and methods, and deleting some existing fields.
    045     * <p/>
    046     * A ClassTransformation contains all the state data specific to a particular class being transformed. A number of
    047     * <em>workers</em> will operate upon the ClassTransformation to effect the desired changes before the true class is
    048     * loaded into memory.
    049     * <p/>
    050     * Instances of this class are not designed to be thread safe, access to an instance should be restricted to a single
    051     * thread. In fact, the design of this type is to allow stateless singletons in multiple threads to work on
    052     * thread-specific data (within the ClassTransformation).
    053     * <p/>
    054     * The majority of methods concern the <em>declared</em> members (field and methods) of a specific class, rather than
    055     * any fields or methods inherited from a base class.
    056     *
    057     * @deprecated In 5.3
    058     * @see PlasticClass
    059     */
    060    public interface ClassTransformation extends AnnotationProvider
    061    {
    062        /**
    063         * Returns the fully qualified class name of the class being transformed.
    064         */
    065        String getClassName();
    066
    067        /**
    068         * Returns the name of a new member (field or method). Ensures that the resulting name does not
    069         * conflict with any
    070         * existing member (declared by the underlying class, or inherited from a base class).
    071         *
    072         * @param suggested
    073         *            the suggested value for the member
    074         * @return a unique name for the member
    075         */
    076        String newMemberName(String suggested);
    077
    078        /**
    079         * As with {@link #newMemberName(String)}, but the suggested name is constructed from the prefix
    080         * and base name. An
    081         * underscore will separate the prefix from the base name.
    082         *
    083         * @param prefix
    084         *            for the generated name
    085         * @param baseName
    086         *            a name, often of an existing field or method
    087         * @return a unique name
    088         */
    089        String newMemberName(String prefix, String baseName);
    090
    091        /**
    092         * Returns a sorted list of declared instance fields with the indicated annotation. Non-private
    093         * and static fields are ignored.
    094         *
    095         * @since 5.2.0
    096         */
    097        List<TransformField> matchFieldsWithAnnotation(Class<? extends Annotation> annotationClass);
    098
    099        /**
    100         * Finds all methods matched by the provided predicate.
    101         *
    102         * @param predicate
    103         *            Used to filter the list
    104         * @return a list of matching methods (which may be empty) in ascending order (by
    105         *         method name), but descending order (by parameter count) within overrides of a single method name.
    106         */
    107        List<TransformMethod> matchMethods(Predicate<TransformMethod> predicate);
    108
    109        /**
    110         * Finds all methods matched by the provided predicate.
    111         *
    112         * @param annotationType
    113         *            Used to filter the list
    114         * @return a list of matching methods (which may be empty) in ascending order (by
    115         *         method name), but descending order (by parameter count) within overrides of a single method name.
    116         */
    117        List<TransformMethod> matchMethodsWithAnnotation(Class<? extends Annotation> annotationType);
    118
    119        /**
    120         * Finds all unclaimed fields matched by the provided predicate. Only considers instance fields.
    121         * Added, removed and claimed fields are excluded.
    122         *
    123         * @param predicate
    124         *            used for matching
    125         * @return sorted list of matching fields
    126         * @since 5.2.0
    127         */
    128        List<TransformField> matchFields(Predicate<TransformField> predicate);
    129
    130        /**
    131         * Locates a declared field by its field name. The field must exist.
    132         *
    133         * @param fieldName
    134         *            of declared field
    135         * @return field information
    136         * @throws RuntimeException
    137         *             if no such field
    138         * @since 5.2.0
    139         */
    140        TransformField getField(String fieldName);
    141
    142        /**
    143         * Matches all fields that are not claimed. This may include static fields and final fields, but will not
    144         * include fields that have been added as part of the transformation.
    145         *
    146         * @since 5.2.0
    147         * @return sorted list of unclaimed fields
    148         */
    149        List<TransformField> matchUnclaimedFields();
    150
    151        /**
    152         * Returns true if the indicated name is a private instance field.
    153         *
    154         * @return true if field exists
    155         */
    156        boolean isField(String fieldName);
    157
    158        /**
    159         * Defines a new declared field for the class. Suggested name may be modified to ensure uniqueness.
    160         *
    161         * @param modifiers
    162         *            modifiers for the field (typically, {@link java.lang.reflect.Modifier#PRIVATE})
    163         * @param type
    164         *            the type for the field, as a string
    165         * @param suggestedName
    166         *            the desired name for the field, which may be modified (for uniqueness) when
    167         *            returned
    168         * @return new field instance
    169         */
    170        TransformField createField(int modifiers, String type, String suggestedName);
    171
    172        /**
    173         * Defines a new <strong>protected</strong> instance variable whose initial value is provided
    174         * statically, via a
    175         * constructor parameter. The transformation caches the result, so calling this method
    176         * repeatedly with the same type
    177         * and value will return the same field name. Caching extends to the parent transformation, so
    178         * that a value injected
    179         * into a parent class will be available (via the protected instance variable) to subclasses.
    180         * This is primarily used to inject service dependencies into components, though it has a number
    181         * of other uses as well.
    182         *
    183         * @param type
    184         *            the type of object to inject
    185         * @param suggestedName
    186         *            the suggested name for the new field
    187         * @param value
    188         *            to be injected. This value is retained.
    189         * @return the actual name of the injected field
    190         */
    191        String addInjectedField(Class type, String suggestedName, Object value);
    192
    193        /**
    194         * Like {@link #addInjectedField(Class, String, Object)}, but instead of specifying the value,
    195         * a provider for the value is specified. In the generated class' constructor, the provider
    196         * will be passed the {@link ComponentResources} and will return the final value; thus
    197         * each component <em>instance</em> will receive a matching unique instance via the provider.
    198         *
    199         * @param type
    200         *            type of value to inject
    201         * @param suggestedName
    202         *            suggested name for the new field
    203         * @param provider
    204         *            injected into the component to provide the value
    205         * @return the actual name of the injected field
    206         * @since 5.2.0
    207         */
    208        <T> TransformField addIndirectInjectedField(Class<T> type, String suggestedName, ComponentValueProvider<T> provider);
    209
    210        /**
    211         * Transforms the class to implement the indicated interface. If the class (or its super class)
    212         * does not already
    213         * implement the interface, then the interface is added, and default implementations of any
    214         * methods of the interface
    215         * are added.
    216         * <p/>
    217         * TODO: Checking that the names of methods in the interface do not conflict with the names of methods present in
    218         * the (unmodified) class.
    219         *
    220         * @param interfaceClass
    221         *            the interface to be implemented by the class
    222         * @throws IllegalArgumentException
    223         *             if the interfaceClass argument does not represent an interface
    224         */
    225        void addImplementedInterface(Class interfaceClass);
    226
    227        /**
    228         * Converts a type name into a corresponding class (possibly, a transformed class). Primitive
    229         * type names are returned as wrapper types.
    230         */
    231        Class toClass(String type);
    232
    233        /**
    234         * Returns a logger, based on the class name being transformed, to which warnings or errors
    235         * concerning the class being transformed may be logged.
    236         */
    237        Logger getLogger();
    238
    239        /**
    240         * Returns true if this transformation represents a root class (one that extends directly from
    241         * Object), or false if this transformation is an sub-class of another transformed class.
    242         *
    243         * @return true if root class, false if sub-class
    244         */
    245        boolean isRootTransformation();
    246
    247        /**
    248         * Locates and returns the method if declared in this class; If not,
    249         * the method is added to the class. If the method is an override
    250         * of a base class method, then the method will delegate to the base
    251         * class method (invoke it, return its value). If the method is entirely
    252         * new, it will ignore its parameters and return a default value (null, 0 or false).
    253         *
    254         * @param signature
    255         *            identifies the method to locate, override or create
    256         * @since 5.2.0
    257         */
    258        TransformMethod getOrCreateMethod(TransformMethodSignature signature);
    259
    260        /**
    261         * Determines if the class being transformed includes a declared (not inherited) method
    262         * with the provided signature.
    263         *
    264         * @since 5.2.0
    265         * @param signature
    266         *            identifies method to search for
    267         * @return true if a such a method exists
    268         */
    269        boolean isDeclaredMethod(TransformMethodSignature signature);
    270
    271        /**
    272         * Adds advice to the {@link Component#dispatchComponentEvent(org.apache.tapestry5.runtime.ComponentEvent)} method.
    273         * If the handler is invoked,
    274         * the return value of the method will be overriden to true. Updates
    275         * {@linkplain MutableComponentModel#addEventHandler(String) the model} to
    276         * indicate that there is a handler for the named event. Existing handlers, or super-class handlers,
    277         * are invoked <em>first</em>.
    278         *
    279         * @param eventType
    280         *            name of event to be handled
    281         * @param minContextValues
    282         *            minimum number of event context values required to invoke the method
    283         * @param methodDescription
    284         *            Text description of what the handler does (used with {@link Event#setMethodDescription(String)})
    285         * @param handler
    286         *            the handler to invoke
    287         * @since 5.2.0
    288         */
    289        void addComponentEventHandler(String eventType, int minContextValues, String methodDescription,
    290                ComponentEventHandler handler);
    291    }