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        {
049            _primitiveParser.put(boolean.class, "java.lang.Boolean.parseBoolean");
050            _primitiveParser.put(short.class, "java.lang.Short.parseShort");
051            _primitiveParser.put(int.class, "java.lang.Integer.parseInt");
052            _primitiveParser.put(long.class, "java.lang.Long.parseLong");
053            _primitiveParser.put(double.class, "java.lang.Double.parseDouble");
054            _primitiveParser.put(float.class, "java.lang.Float.parseFloat");
055        }
056    
057        public void performEnhancement(EnhancementOperation op, InjectSpecification spec)
058        {
059            String propertyName = spec.getProperty();
060            String metaKey = spec.getObject();
061    
062            injectMetaValue(op, propertyName, metaKey, spec.getLocation());
063        }
064    
065        public void injectMetaValue(EnhancementOperation op, String propertyName, String metaKey,
066                Location location)
067        {
068            Defense.notNull(op, "op");
069            Defense.notNull(propertyName, "propertyName");
070            Defense.notNull(metaKey, "metaKey");
071    
072            Class propertyType = op.getPropertyType(propertyName);
073    
074            op.claimReadonlyProperty(propertyName);
075    
076            String sourceName = op
077                    .addInjectedField(SOURCE_NAME, ComponentPropertySource.class, _source);
078    
079            MethodSignature sig = new MethodSignature(propertyType, op
080                    .getAccessorMethodName(propertyName), null, null);
081    
082            String parser = (String) _primitiveParser.get(propertyType);
083    
084            if (parser != null)
085            {
086                addPrimitive(op, metaKey, propertyName, sig, sourceName, parser, location);
087                return;
088            }
089    
090            if (propertyType == char.class)
091            {
092                addCharacterPrimitive(op, metaKey, propertyName, sig, sourceName, location);
093                return;
094            }
095    
096            addObject(op, metaKey, propertyName, propertyType, sig, sourceName, location);
097        }
098    
099        private void addPrimitive(EnhancementOperation op, String metaKey, String propertyName,
100                MethodSignature sig, String sourceName, String parser, Location location)
101        {
102            BodyBuilder builder = new BodyBuilder();
103            builder.begin();
104            builder.addln(
105                    "java.lang.String meta = {0}.getComponentProperty(this, \"{1}\");",
106                    sourceName,
107                    metaKey);
108            builder.addln("return {0}(meta);", parser);
109            builder.end();
110    
111            op.addMethod(Modifier.PUBLIC, sig, builder.toString(), location);
112        }
113    
114        private void addCharacterPrimitive(EnhancementOperation op, String metaKey,
115                String propertyName, MethodSignature sig, String sourceName, Location location)
116        {
117            BodyBuilder builder = new BodyBuilder();
118            builder.begin();
119            builder.addln(
120                    "java.lang.String meta = {0}.getComponentProperty(this, \"{1}\");",
121                    sourceName,
122                    metaKey);
123            builder.addln("return meta.charAt(0);");
124            builder.end();
125    
126            op.addMethod(Modifier.PUBLIC, sig, builder.toString(), location);
127        }
128    
129        private void addObject(EnhancementOperation op, String metaKey, String propertyName,
130                Class propertyType, MethodSignature sig, String sourceName, Location location)
131        {
132            String valueConverterName = op.addInjectedField(
133                    "_$valueConverter",
134                    ValueConverter.class,
135                    _valueConverter);
136            String classRef = op.getClassReference(propertyType);
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 ({0}) {1}.coerceValue(meta, {2});", ClassFabUtils
145                    .getJavaClassName(propertyType), valueConverterName, classRef);
146            builder.end();
147    
148            op.addMethod(Modifier.PUBLIC, sig, builder.toString(), location);
149        }
150    
151        public void setSource(ComponentPropertySource source)
152        {
153            _source = source;
154        }
155    
156        public void setValueConverter(ValueConverter valueConverter)
157        {
158            _valueConverter = valueConverter;
159        }
160    }