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 }