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 static org.easymock.EasyMock.expect; 018 import static org.easymock.EasyMock.expectLastCall; 019 020 import java.lang.reflect.Modifier; 021 import java.util.ArrayList; 022 import java.util.Collections; 023 import java.util.Iterator; 024 import java.util.List; 025 026 import org.apache.hivemind.ApplicationRuntimeException; 027 import org.apache.hivemind.ErrorLog; 028 import org.apache.hivemind.Location; 029 import org.apache.hivemind.service.BodyBuilder; 030 import org.apache.hivemind.service.MethodSignature; 031 import org.apache.tapestry.BaseComponent; 032 import org.apache.tapestry.BaseComponentTestCase; 033 import org.apache.tapestry.IBinding; 034 import org.apache.tapestry.IComponent; 035 import org.apache.tapestry.binding.BindingSource; 036 import org.apache.tapestry.event.PageDetachListener; 037 import org.apache.tapestry.spec.IComponentSpecification; 038 import org.apache.tapestry.spec.IPropertySpecification; 039 import org.apache.tapestry.spec.PropertySpecification; 040 import org.testng.annotations.Test; 041 042 /** 043 * Tests for {@link org.apache.tapestry.enhance.SpecifiedPropertyWorker}. 044 * 045 * @author Howard M. Lewis Ship 046 * @since 4.0 047 */ 048 @Test 049 public class TestSpecifiedPropertyWorker extends BaseComponentTestCase 050 { 051 private List buildPropertySpecs(String name, String type, boolean persistent) 052 { 053 return buildPropertySpecs(name, type, persistent, null, null); 054 } 055 056 private List buildPropertySpecs(String name, String type, boolean persistent, 057 Location location, String initialValue) 058 { 059 PropertySpecification ps = new PropertySpecification(); 060 ps.setName(name); 061 ps.setType(type); 062 ps.setPersistence(persistent ? "session" : null); 063 ps.setInitialValue(initialValue); 064 ps.setLocation(location); 065 066 return Collections.singletonList(ps); 067 } 068 069 private IComponentSpecification buildComponentSpecification(List propertySpecs) 070 { 071 List names = new ArrayList(); 072 Iterator i = propertySpecs.iterator(); 073 while (i.hasNext()) 074 { 075 IPropertySpecification ps = (IPropertySpecification) i.next(); 076 077 names.add(ps.getName()); 078 } 079 080 IComponentSpecification result = newSpec(); 081 082 expect(result.getPropertySpecificationNames()).andReturn(names); 083 084 i = propertySpecs.iterator(); 085 while (i.hasNext()) 086 { 087 IPropertySpecification ps = (IPropertySpecification) i.next(); 088 089 expect(result.getPropertySpecification(ps.getName())).andReturn(ps); 090 } 091 092 return result; 093 } 094 095 private IComponentSpecification buildComponentSpecification(String name, String type, 096 boolean persistent) 097 { 098 return buildComponentSpecification(buildPropertySpecs(name, type, persistent)); 099 } 100 101 public enum TestEnum { 102 First, 103 Second 104 } 105 106 public void test_Can_Proxy_Enum() 107 { 108 Object obj = TestEnum.First; 109 110 assert !EnhanceUtils.canProxyPropertyType(obj.getClass()); 111 assert EnhanceUtils.canProxyPropertyType(List.class); 112 } 113 114 public void testAddNormal() throws Exception 115 { 116 Location l = newLocation(); 117 118 IComponentSpecification spec = buildComponentSpecification(buildPropertySpecs( 119 "fred", 120 "boolean", 121 false, 122 l, 123 null)); 124 125 // Training 126 EnhancementOperation op = newMock(EnhancementOperation.class); 127 128 expect(op.convertTypeName("boolean")).andReturn(boolean.class); 129 130 op.validateProperty("fred", boolean.class); 131 op.claimProperty("fred"); 132 op.addField("_$fred", boolean.class); 133 134 expect(op.getAccessorMethodName("fred")).andReturn("isFred"); 135 136 op.addMethod( 137 Modifier.PUBLIC, 138 new MethodSignature(boolean.class, "isFred", null, null), 139 "return _$fred;", 140 l); 141 142 op.addMethod(Modifier.PUBLIC, new MethodSignature(void.class, "setFred", new Class[] 143 { boolean.class }, null), "{\n _$fred = $1;\n}\n", l); 144 145 op.addField("_$fred$default", boolean.class); 146 147 op.extendMethodImplementation( 148 IComponent.class, 149 EnhanceUtils.FINISH_LOAD_SIGNATURE, 150 "_$fred$default = _$fred;"); 151 152 op.extendMethodImplementation( 153 PageDetachListener.class, 154 EnhanceUtils.PAGE_DETACHED_SIGNATURE, 155 "_$fred = _$fred$default;"); 156 157 replay(); 158 159 SpecifiedPropertyWorker w = new SpecifiedPropertyWorker(); 160 161 w.performEnhancement(op, spec); 162 163 verify(); 164 } 165 166 public void testAddWithInitialValue() throws Exception 167 { 168 BindingSource bs = newMock(BindingSource.class); 169 Location l = fabricateLocation(12); 170 171 IComponentSpecification spec = buildComponentSpecification(buildPropertySpecs( 172 "fred", 173 "java.util.List", 174 false, 175 l, 176 "ognl:foo()")); 177 178 InitialValueBindingCreator expectedCreator = new InitialValueBindingCreator(bs, 179 EnhanceMessages.initialValueForProperty("fred"), "ognl:foo()", l); 180 181 // Training 182 183 EnhancementOperation op = newMock(EnhancementOperation.class); 184 185 expect(op.convertTypeName("java.util.List")).andReturn(List.class); 186 187 op.validateProperty("fred", List.class); 188 op.claimProperty("fred"); 189 op.addField("_$fred", List.class); 190 191 expect(op.getAccessorMethodName("fred")).andReturn("getFred"); 192 193 op.addMethod( 194 Modifier.PUBLIC, 195 new MethodSignature(List.class, "getFred", null, null), 196 "return _$fred;", 197 l); 198 199 op.addMethod(Modifier.PUBLIC, new MethodSignature(void.class, "setFred", new Class[] 200 { List.class }, null), "{\n _$fred = $1;\n}\n", l); 201 202 expect(op.addInjectedField( 203 "_$fred$initialValueBindingCreator", 204 InitialValueBindingCreator.class, 205 expectedCreator)).andReturn("_$fred$initialValueBindingCreator"); 206 207 op.addField("_$fred$initialValueBinding", IBinding.class); 208 op 209 .extendMethodImplementation( 210 IComponent.class, 211 EnhanceUtils.FINISH_LOAD_SIGNATURE, 212 "_$fred$initialValueBinding = _$fred$initialValueBindingCreator.createBinding(this);\n"); 213 214 expect(op.getClassReference(List.class)).andReturn("_$class$java$util$List"); 215 216 String code = "_$fred = (java.util.List) _$fred$initialValueBinding.getObject(_$class$java$util$List);\n"; 217 218 op.extendMethodImplementation(IComponent.class, EnhanceUtils.FINISH_LOAD_SIGNATURE, code); 219 op.extendMethodImplementation( 220 PageDetachListener.class, 221 EnhanceUtils.PAGE_DETACHED_SIGNATURE, 222 code); 223 224 replay(); 225 226 SpecifiedPropertyWorker w = new SpecifiedPropertyWorker(); 227 w.setBindingSource(bs); 228 229 w.performEnhancement(op, spec); 230 231 verify(); 232 } 233 234 public void test_Add_Persistent() throws Exception 235 { 236 IComponentSpecification spec = buildComponentSpecification( 237 "barney", 238 "java.lang.String", 239 true); 240 241 // Training 242 243 EnhancementOperation op = newMock(EnhancementOperation.class); 244 245 expect(op.convertTypeName("java.lang.String")).andReturn(String.class); 246 247 op.validateProperty("barney", String.class); 248 op.claimProperty("barney"); 249 op.addField("_$barney", String.class); 250 251 expect(op.getAccessorMethodName("barney")).andReturn("getBarney"); 252 253 op.addMethod( 254 Modifier.PUBLIC, 255 new MethodSignature(String.class, "getBarney", null, null), 256 "return _$barney;", 257 null); 258 259 BodyBuilder b = new BodyBuilder(); 260 b.begin(); 261 /* 262 b.addln("if ($1 != null && org.apache.tapestry.record.ObservedProperty.class.isAssignableFrom($1.getClass())) {"); 263 b.add(" $1 = (" + ClassFabUtils.getJavaClassName(String.class) + ")((org.apache.tapestry.record.ObservedProperty)$1)"); 264 b.addln(".getCGProperty();"); 265 b.addln("}"); 266 */ 267 b.addln("org.apache.tapestry.Tapestry#fireObservedChange(this, \"barney\", ($w) $1);"); 268 b.addln("_$barney = $1;"); 269 b.end(); 270 271 op.addMethod(Modifier.PUBLIC, new MethodSignature(void.class, "setBarney", new Class[] 272 { String.class }, null), b.toString(), null); 273 274 op.addField("_$barney$default", String.class); 275 276 op.extendMethodImplementation( 277 IComponent.class, 278 EnhanceUtils.FINISH_LOAD_SIGNATURE, 279 "_$barney$default = _$barney;"); 280 281 op.extendMethodImplementation( 282 PageDetachListener.class, 283 EnhanceUtils.PAGE_DETACHED_SIGNATURE, 284 "_$barney = _$barney$default;"); 285 286 replay(); 287 288 SpecifiedPropertyWorker w = new SpecifiedPropertyWorker(); 289 290 w.performEnhancement(op, spec); 291 292 verify(); 293 } 294 295 public void testFailure() throws Exception 296 { 297 Location l = fabricateLocation(207); 298 // Should be "java.lang.Long" 299 List propertySpecs = buildPropertySpecs("wilma", "Long", false, l, null); 300 IComponentSpecification spec = buildComponentSpecification(propertySpecs); 301 302 EnhancementOperation op = newMock(EnhancementOperation.class); 303 304 op.convertTypeName("Long"); 305 Throwable ex = new ApplicationRuntimeException("Simulated error."); 306 expectLastCall().andThrow(ex); 307 308 309 expect(op.getBaseClass()).andReturn(BaseComponent.class); 310 311 ErrorLog log = newMock(ErrorLog.class); 312 313 log 314 .error( 315 "Error adding property wilma to class org.apache.tapestry.BaseComponent: Simulated error.", 316 l, 317 ex); 318 319 replay(); 320 321 SpecifiedPropertyWorker w = new SpecifiedPropertyWorker(); 322 w.setErrorLog(log); 323 324 w.performEnhancement(op, spec); 325 326 verify(); 327 } 328 329 }