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
015package org.apache.tapestry.enhance;
016
017import java.lang.reflect.Modifier;
018import java.util.HashMap;
019import java.util.Map;
020
021import org.apache.hivemind.Location;
022import org.apache.hivemind.service.BodyBuilder;
023import org.apache.hivemind.service.ClassFabUtils;
024import org.apache.hivemind.service.MethodSignature;
025import org.apache.hivemind.util.Defense;
026import org.apache.tapestry.coerce.ValueConverter;
027import org.apache.tapestry.services.ComponentPropertySource;
028import 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 */
038public 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}