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}