001/**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.xbean.propertyeditor;
018
019import java.text.DateFormat;
020import java.text.ParseException;
021import java.text.SimpleDateFormat;
022import java.util.Date;
023import java.util.Locale;
024import java.util.List;
025import java.util.ArrayList;
026
027/**
028 * A property editor for Date typed properties.
029 * 
030 * @version $Rev$ $Date$
031 */
032public class DateEditor extends AbstractConverter {
033
034    private List<DateFormat> formats = new ArrayList<DateFormat>();
035
036    public DateEditor() {
037        super(Date.class);
038
039        formats.add(DateFormat.getInstance());
040        formats.add(DateFormat.getDateInstance());
041        formats.add(new SimpleDateFormat("yyyy-MM-dd")); // Atom (ISO 8601))) -- short version;
042        formats.add(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssz")); // Atom (ISO 8601)));
043    }
044
045    /**
046     * Convert the text value of the property into a Date object instance.
047     * 
048     * @return a Date object constructed from the property text value.
049     * @throws PropertyEditorException
050     *                 Unable to parse the string value into a Date.
051     */
052    protected Object toObjectImpl(String text) {
053        for (DateFormat format : formats) {
054            try {
055                return format.parse(text);
056            } catch (ParseException e) {
057            }
058        }
059
060        try {
061            return complexParse(text);
062        } catch (ParseException e) {
063            // any format errors show up as a ParseException, which we turn into
064            // a PropertyEditorException.
065            throw new PropertyEditorException(e);
066        }
067    }
068
069    private Object complexParse(String text) throws ParseException {
070        // find out whether the first token is a locale id and style in that
071        // order
072        // if there's locale, style is mandatory
073        Locale locale = Locale.getDefault();
074        int style = DateFormat.MEDIUM;
075        int firstSpaceIndex = text.indexOf(' ');
076        if (firstSpaceIndex != -1) {
077            String token = text.substring(0, firstSpaceIndex).intern();
078            if (token.startsWith("locale")) {
079                String localeStr = token.substring(token.indexOf('=') + 1);
080                int underscoreIndex = localeStr.indexOf('_');
081                if (underscoreIndex != -1) {
082                    String language = localeStr.substring(0, underscoreIndex);
083                    String country = localeStr.substring(underscoreIndex + 1);
084                    locale = new Locale(language, country);
085                } else {
086                    locale = new Locale(localeStr);
087                }
088                // locale is followed by mandatory style
089                int nextSpaceIndex = text.indexOf(' ', firstSpaceIndex + 1);
090                token = text.substring(firstSpaceIndex + 1, nextSpaceIndex);
091                String styleStr = token.substring(token.indexOf('=') + 1);
092                if (styleStr.equalsIgnoreCase("SHORT")) {
093                    style = DateFormat.SHORT;
094                } else if (styleStr.equalsIgnoreCase("MEDIUM")) {
095                    style = DateFormat.MEDIUM;
096                } else if (styleStr.equalsIgnoreCase("LONG")) {
097                    style = DateFormat.LONG;
098                } else if (styleStr.equalsIgnoreCase("FULL")) {
099                    style = DateFormat.FULL;
100                } else {
101                    // unknown style name
102                    // throw exception or assume default?
103                    style = DateFormat.MEDIUM;
104                }
105                text = text.substring(nextSpaceIndex + 1);
106            }
107        }
108        DateFormat formats = DateFormat.getDateInstance(style, locale);
109        return formats.parse(text);
110    }
111
112    protected String toStringImpl(Object value) {
113        Date date = (Date) value;
114        String text = formats.get(0).format(date);
115        return text;
116    }
117}