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    }