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 }