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