001 // Copyright 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 java.lang.reflect.Modifier; 018 import java.util.HashMap; 019 import java.util.Map; 020 021 import org.apache.hivemind.Location; 022 import org.apache.hivemind.service.BodyBuilder; 023 import org.apache.hivemind.service.ClassFabUtils; 024 import org.apache.hivemind.service.MethodSignature; 025 import org.apache.hivemind.util.Defense; 026 import org.apache.tapestry.coerce.ValueConverter; 027 import org.apache.tapestry.services.ComponentPropertySource; 028 import org.apache.tapestry.spec.InjectSpecification; 029 030 /** 031 * Injects meta data obtained via {@link org.apache.tapestry.services.ComponentPropertySource} 032 * (meaning that meta-data is searched for in the component's specification, then it's namespace 033 * (library or application specification), then the global application properties. 034 * 035 * @author Howard M. Lewis Ship 036 * @since 4.0 037 */ 038 public class InjectMetaWorker implements InjectEnhancementWorker 039 { 040 static final String SOURCE_NAME = "_$componentPropertySource"; 041 042 private ComponentPropertySource _source; 043 044 private ValueConverter _valueConverter; 045 046 private Map _primitiveParser = new HashMap(); 047 { 048 _primitiveParser.put(short.class, "java.lang.Short.parseShort"); 049 _primitiveParser.put(int.class, "java.lang.Integer.parseInt"); 050 _primitiveParser.put(long.class, "java.lang.Long.parseLong"); 051 _primitiveParser.put(double.class, "java.lang.Double.parseDouble"); 052 _primitiveParser.put(float.class, "java.lang.Float.parseFloat"); 053 } 054 055 public void performEnhancement(EnhancementOperation op, InjectSpecification spec) 056 { 057 String propertyName = spec.getProperty(); 058 String metaKey = spec.getObject(); 059 060 injectMetaValue(op, propertyName, metaKey, spec.getLocation()); 061 } 062 063 public void injectMetaValue(EnhancementOperation op, String propertyName, String metaKey, 064 Location location) 065 { 066 Defense.notNull(op, "op"); 067 Defense.notNull(propertyName, "propertyName"); 068 Defense.notNull(metaKey, "metaKey"); 069 070 Class propertyType = op.getPropertyType(propertyName); 071 072 // Default to object if not specified 073 074 if (propertyType == null) { 075 076 propertyType = Object.class; 077 } 078 079 op.claimReadonlyProperty(propertyName); 080 081 String sourceName = op.addInjectedField(SOURCE_NAME, ComponentPropertySource.class, _source); 082 083 MethodSignature sig = new MethodSignature(propertyType, op.getAccessorMethodName(propertyName), null, null); 084 085 String parser = (String) _primitiveParser.get(propertyType); 086 087 if (parser != null) 088 { 089 addPrimitive(op, metaKey, propertyName, sig, sourceName, parser, location); 090 return; 091 } else if (propertyType == boolean.class) 092 { 093 addBoolean(op, metaKey, propertyName, sig, sourceName, location); 094 return; 095 } 096 097 if (propertyType == char.class) 098 { 099 addCharacterPrimitive(op, metaKey, propertyName, sig, sourceName, location); 100 return; 101 } 102 103 addObject(op, metaKey, propertyName, propertyType, sig, sourceName, location); 104 } 105 106 private void addPrimitive(EnhancementOperation op, String metaKey, String propertyName, 107 MethodSignature sig, String sourceName, String parser, Location location) 108 { 109 BodyBuilder builder = new BodyBuilder(); 110 builder.begin(); 111 builder.addln( 112 "java.lang.String meta = {0}.getComponentProperty(this, \"{1}\");", 113 sourceName, 114 metaKey); 115 builder.addln("return {0}(meta);", parser); 116 builder.end(); 117 118 op.addMethod(Modifier.PUBLIC, sig, builder.toString(), location); 119 } 120 121 private void addBoolean(EnhancementOperation op, String metaKey, String propertyName, 122 MethodSignature sig, String sourceName, Location location) 123 { 124 BodyBuilder builder = new BodyBuilder(); 125 builder.begin(); 126 builder.addln( 127 "java.lang.String meta = {0}.getComponentProperty(this, \"{1}\");", 128 sourceName, 129 metaKey); 130 builder.addln("return java.lang.Boolean.valueOf(meta).booleanValue();"); 131 builder.end(); 132 133 op.addMethod(Modifier.PUBLIC, sig, builder.toString(), location); 134 } 135 136 private void addCharacterPrimitive(EnhancementOperation op, String metaKey, 137 String propertyName, MethodSignature sig, String sourceName, Location location) 138 { 139 BodyBuilder builder = new BodyBuilder(); 140 builder.begin(); 141 builder.addln( 142 "java.lang.String meta = {0}.getComponentProperty(this, \"{1}\");", 143 sourceName, 144 metaKey); 145 builder.addln("return meta.charAt(0);"); 146 builder.end(); 147 148 op.addMethod(Modifier.PUBLIC, sig, builder.toString(), location); 149 } 150 151 private void addObject(EnhancementOperation op, String metaKey, String propertyName, 152 Class propertyType, MethodSignature sig, String sourceName, Location location) 153 { 154 String valueConverterName = op.addInjectedField("_$valueConverter", ValueConverter.class, _valueConverter); 155 156 String classRef = op.getClassReference(propertyType); 157 158 BodyBuilder builder = new BodyBuilder(); 159 builder.begin(); 160 builder.addln("java.lang.String meta = {0}.getComponentProperty(this, \"{1}\");", 161 sourceName, 162 metaKey); 163 builder.addln("return ({0}) {1}.coerceValue(meta, {2});", ClassFabUtils 164 .getJavaClassName(propertyType), valueConverterName, classRef); 165 builder.end(); 166 167 op.addMethod(Modifier.PUBLIC, sig, builder.toString(), location); 168 } 169 170 public void setSource(ComponentPropertySource source) 171 { 172 _source = source; 173 } 174 175 public void setValueConverter(ValueConverter valueConverter) 176 { 177 _valueConverter = valueConverter; 178 } 179 }