001    // Copyright 2004, 2005 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.tapestry.enhance;
016    
017    import org.apache.hivemind.Location;
018    import org.apache.hivemind.service.MethodSignature;
019    
020    import java.util.List;
021    
022    /**
023     * A process object representing enhancements to a component class. The
024     * operation is passed to {@link org.apache.tapestry.enhance.EnhancementWorker}objects
025     * that perform enhancements.
026     * 
027     * @author Howard M. Lewis Ship
028     * @since 4.0
029     */
030    public interface EnhancementOperation
031    {
032    
033        /**
034         * Claims a property. Most enhancements are concerned with adding
035         * properties. Some enhancement workers exist to fill in defaults, and they
036         * need to know what properties have already been spoken for by eariler
037         * enhancement works.
038         * 
039         * @throws org.apache.hivemind.ApplicationRuntimeException
040         *             if the property was previously claimed
041         */
042    
043        void claimProperty(String propertyName);
044    
045        /**
046         * Claims a property as read-only. This will check to see if the property
047         * has an abstract setter method.
048         * 
049         * @throws org.apache.hivemind.ApplicationRuntimeException
050         *             if the property was previously claimed, or if the property
051         *             includes an accessor method.
052         */
053    
054        void claimReadonlyProperty(String propertyName);
055        
056        /**
057         * Checks to see if the specified property can be claimed as read only. 
058         * 
059         * @param propertyName
060         *          The property to check.
061         * 
062         * @return True, if no setter method has been created for the specified property and
063         *          the property hasn't been claimed by someone else.
064         */
065        boolean canClaimAsReadOnlyProperty(String propertyName);
066        
067        /**
068         * Returns a list of the names of existing properties that are not claimed
069         * and which have abstract accessor methods.
070         */
071    
072        List findUnclaimedAbstractProperties();
073    
074        /**
075         * Adds a field to the enhanced class; the field will be private and use the
076         * provided name and type.
077         */
078    
079        void addField(String name, Class type);
080    
081        /**
082         * Adds a field containing an initial value, which is injected into the
083         * class via its fabricated constructor. This method may be called multiple
084         * times with the same value and will return the same variable name (an
085         * identity map is kept internally).
086         * 
087         * @param fieldName
088         *            The default name for the field, used if a new field (and
089         *            contructor argument) is being created. Only used if a field
090         *            for the value doesn't exist.
091         * @param fieldType
092         *            The type of the field to be created.
093         * @param value
094         *            the value to be referenced, which may not be null
095         * @return the name of the field containing the value. This may or may not
096         *         match fieldName. The provided fieldName may be modified to
097         *         prevent naming conflicts.
098         */
099    
100        String addInjectedField(String fieldName, Class fieldType, Object value);
101    
102        /**
103         * Converts a type name (an object class name, a primtive name, or an array)
104         * into the corresponding Class object.
105         */
106    
107        Class convertTypeName(String type);
108    
109        /**
110         * Confirms that the named property either doesn't exist (in the component
111         * base class), or that the type of the property exactly matches the
112         * indicated type.
113         */
114    
115        void validateProperty(String name, Class expectedType);
116    
117        /**
118         * Returns the name of the accessor method for the given property (if it
119         * exists in the component base class), or fabricates a new name if it does
120         * not.
121         *
122         * @param propertyName
123         *          The property to get an accessor method name of.
124         *
125         * @return The existing/future name of an appropriate accessor method for the property.
126         */
127    
128        String getAccessorMethodName(String propertyName);
129    
130        /**
131         * Adds a method to the enhanced class.
132         * 
133         * @param modifier
134         *            as defined by {@link java.lang.reflect.Modifier}, typically
135         *            {@link java.lang.reflect.Modifier#PUBLIC}
136         * @param sig
137         *            the method signature (defining name, return type, etc.)
138         * @param methodBody
139         *            a Javassist code snippet for the method body
140         * @param location
141         *            a location used to identify "why" the method was added; the
142         *            location may later be used to describe conflicts. May not be
143         *            null.
144         */
145        void addMethod(int modifier, MethodSignature sig, String methodBody, Location location);
146    
147        /**
148         * Returns the base component class, as defined in the specification (or
149         * defaulted). An enhaced subclass of the component class will usually be
150         * created.
151         *
152         * @return The class this enhancement operation is operating on.
153         */
154        Class getBaseClass();
155    
156        /**
157         * Returns a reference to a particular class. This will, effectively, by the
158         * name of a private field.
159         *
160         * @param clazz The class to get a string equivalent reference of.
161         *
162         * @return The enhancement (javassist) compatiable string version of the specified class.
163         */
164    
165        String getClassReference(Class clazz);
166    
167        /**
168         * Returns the type of an existing property of the base component class. If
169         * the property does not exist, then returns null.
170         *
171         * @param name
172         *          The property name.
173         * 
174         * @return The property type, or null if it doesn't exist.
175         */
176    
177        Class getPropertyType(String name);
178    
179        /**
180         * Allows for a kind of distributed construction of a particular method,
181         * within a particular interface. Code can be appended to the method's
182         * implementation throughout the course of the enhancement operation. When
183         * the enhanced class is finialized, the method is added with whatever
184         * contents are in its body. If the base class implements the method, then
185         * the method body will include an initial call to that implementation.
186         * <p>
187         * At this time, this works best for void methods (since there isn't an easy
188         * way to ensure code would be inserted before a final return statement).
189         * 
190         * @param interfaceClass
191         *            the interface containing the method. If the base class does
192         *            not implement the interface, then the enhanced class will have
193         *            the interface added.
194         * @param methodSignature
195         *            the signature of the method to be added.
196         * @param code
197         *            the Javassist markup to be added to the body of the method.
198         */
199        void extendMethodImplementation(Class interfaceClass, MethodSignature methodSignature, String code);
200    
201        /**
202         * Returns true if the class implements the specified interface. Checks the
203         * base class (as identified in the specification), but <em>also</em>
204         * accounts for any additional interfaces that may be added by
205         * {@link #extendMethodImplementation(Class, MethodSignature, String)}.
206         *
207         * @param interfaceClass
208         *          The class to check if the base class implements.
209         *
210         * @return Whether or not the specified interface is implemented by the base class
211         *          being enhanced.
212         */
213    
214        boolean implementsInterface(Class interfaceClass);
215    }