    001// Copyright 2014 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.
    014package org.apache.tapestry5.commons.internal;
    015
    016import java.util.Calendar;
    017import java.util.Date;
    018import java.util.HashMap;
    019import java.util.Map;
    020
    021import org.apache.tapestry5.beaneditor.DataTypeConstants;
    022import org.apache.tapestry5.commons.MappedConfiguration;
    023import org.apache.tapestry5.commons.OrderedConfiguration;
    024import org.apache.tapestry5.commons.internal.services.AnnotationDataTypeAnalyzer;
    025import org.apache.tapestry5.commons.internal.services.DefaultDataTypeAnalyzer;
    026import org.apache.tapestry5.commons.services.DataTypeAnalyzer;
    027import org.apache.tapestry5.commons.services.PropertyAdapter;
    028
    029/**
    030 * Class that provides Tapestry's basic default data type analyzers.
    031 */
    032public class BasicDataTypeAnalyzers
    033{
    034
    035    public static void contributeDataTypeAnalyzer(
    036            OrderedConfiguration<DataTypeAnalyzer> configuration,
    037            DataTypeAnalyzer defaultDataTypeAnalyzer) {
    038        configuration.add("Annotation", new AnnotationDataTypeAnalyzer());
    039        if (defaultDataTypeAnalyzer == null)
    040        {
    041            defaultDataTypeAnalyzer = createDefaultDataTypeAnalyzer();
    042        }
    043        configuration.add("Default", defaultDataTypeAnalyzer, "after:*");
    044    }
    045
    046    public static DataTypeAnalyzer createDefaultDataTypeAnalyzer()
    047    {
    048        DefaultDataTypeAnalyzerMappedConfiguration mappedConfiguration = new DefaultDataTypeAnalyzerMappedConfiguration();
    049        provideDefaultDataTypeAnalyzers(mappedConfiguration);
    050        return new CombinedDataTypeAnalyzer(new AnnotationDataTypeAnalyzer(), new DefaultDataTypeAnalyzer(mappedConfiguration.getMap()));
    051    }
    052
    053    /**
    054     * Maps property types to data type names:
    055     * <ul>
    056     * <li>String --&gt; text
    057     * <li>Number --&gt; number
    058     * <li>Enum --&gt; enum
    059     * <li>Boolean --&gt; boolean
    060     * <li>Date --&gt; date
    061     * </ul>
    062     */
    063    public static void provideDefaultDataTypeAnalyzers(MappedConfiguration<Class, String> configuration)
    064    {
    065        // This is a special case contributed to avoid exceptions when a
    066        // property type can't be
    067        // matched. DefaultDataTypeAnalyzer converts the empty string to null.
    068
    069        configuration.add(Object.class, "");
    070
    071        configuration.add(String.class, DataTypeConstants.TEXT);
    072        configuration.add(Number.class, DataTypeConstants.NUMBER);
    073        configuration.add(Enum.class, DataTypeConstants.ENUM);
    074        configuration.add(Boolean.class, DataTypeConstants.BOOLEAN);
    075        configuration.add(Date.class, DataTypeConstants.DATE);
    076        configuration.add(Calendar.class, DataTypeConstants.CALENDAR);
    077    }
    078
    079    final private static class DefaultDataTypeAnalyzerMappedConfiguration implements MappedConfiguration<Class, String>
    080    {
    081
    082        final Map<Class, String> map = new HashMap<Class, String>();
    083
    084        @Override
    085        public void add(Class key, String value) {
    086            map.put(key, value);
    087        }
    088
    089        @Override
    090        public void override(Class key, String value) {
    091            throw new RuntimeException("Not implemented");
    092        }
    093
    094        @Override
    095        public void addInstance(Class key, Class<? extends String> clazz) {
    096            throw new RuntimeException("Not implemented");
    097        }
    098
    099        @Override
    100        public void overrideInstance(Class key, Class<? extends String> clazz) {
    101            throw new RuntimeException("Not implemented");
    102        }
    103
    104        public Map<Class, String> getMap() {
    105            return map;
    106        }
    107
    108    }
    109
    110    final private static class CombinedDataTypeAnalyzer implements DataTypeAnalyzer
    111    {
    112
    113        final private DataTypeAnalyzer[] analyzers;
    114
    115        public CombinedDataTypeAnalyzer(DataTypeAnalyzer... analyzers)
    116        {
    117                this.analyzers = analyzers;
    118        }
    119
    120        @Override
    121        public String identifyDataType(PropertyAdapter adapter)
    122        {
    123                String type = null;
    124                for (DataTypeAnalyzer analyzer : analyzers)
    125                {
    126                                type = analyzer.identifyDataType(adapter);
    127                                if (type != null)
    128                                {
    129                                        break;
    130                                }
    131                        }
    132                return type;
    133        }
    134
    135    }
    136
    137
    138}