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 }