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    }