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 org.apache.hivemind.Location; 018 import org.apache.hivemind.service.BodyBuilder; 019 import org.apache.hivemind.service.ClassFabUtils; 020 import org.apache.hivemind.service.MethodSignature; 021 import org.apache.hivemind.util.Defense; 022 import org.apache.tapestry.coerce.ValueConverter; 023 import org.apache.tapestry.services.ComponentPropertySource; 024 import org.apache.tapestry.spec.InjectSpecification; 025 026 import java.lang.reflect.Modifier; 027 import java.util.HashMap; 028 import java.util.Map; 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("java.lang.String meta = {0}.getComponentProperty(this, \"{1}\");", 112 sourceName, 113 metaKey); 114 builder.addln("return {0}(meta);", parser); 115 builder.end(); 116 117 op.addMethod(Modifier.PUBLIC, sig, builder.toString(), location); 118 } 119 120 private void addBoolean(EnhancementOperation op, String metaKey, String propertyName, 121 MethodSignature sig, String sourceName, Location location) 122 { 123 BodyBuilder builder = new BodyBuilder(); 124 builder.begin(); 125 builder.addln( 126 "java.lang.String meta = {0}.getComponentProperty(this, \"{1}\");", 127 sourceName, 128 metaKey); 129 builder.addln("return java.lang.Boolean.valueOf(meta).booleanValue();"); 130 builder.end(); 131 132 op.addMethod(Modifier.PUBLIC, sig, builder.toString(), location); 133 } 134 135 private void addCharacterPrimitive(EnhancementOperation op, String metaKey, 136 String propertyName, MethodSignature sig, String sourceName, Location location) 137 { 138 BodyBuilder builder = new BodyBuilder(); 139 builder.begin(); 140 builder.addln( 141 "java.lang.String meta = {0}.getComponentProperty(this, \"{1}\");", 142 sourceName, 143 metaKey); 144 builder.addln("return meta.charAt(0);"); 145 builder.end(); 146 147 op.addMethod(Modifier.PUBLIC, sig, builder.toString(), location); 148 } 149 150 private void addObject(EnhancementOperation op, String metaKey, String propertyName, 151 Class propertyType, MethodSignature sig, String sourceName, Location location) 152 { 153 String valueConverterName = op.addInjectedField("_$valueConverter", ValueConverter.class, _valueConverter); 154 155 String classRef = op.getClassReference(propertyType); 156 157 BodyBuilder builder = new BodyBuilder(); 158 builder.begin(); 159 builder.addln("java.lang.String meta = {0}.getComponentProperty(this, \"{1}\");", 160 sourceName, 161 metaKey); 162 builder.addln("return ({0}) {1}.coerceValue(meta, {2});", ClassFabUtils 163 .getJavaClassName(propertyType), valueConverterName, classRef); 164 builder.end(); 165 166 op.addMethod(Modifier.PUBLIC, sig, builder.toString(), location); 167 } 168 169 public void setSource(ComponentPropertySource source) 170 { 171 _source = source; 172 } 173 174 public void setValueConverter(ValueConverter valueConverter) 175 { 176 _valueConverter = valueConverter; 177 } 178 }