001    package org.apache.fulcrum.intake.model;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one
005     * or more contributor license agreements.  See the NOTICE file
006     * distributed with this work for additional information
007     * regarding copyright ownership.  The ASF licenses this file
008     * to you under the Apache License, Version 2.0 (the
009     * "License"); you may not use this file except in compliance
010     * with the License.  You may obtain a copy of the License at
011     *
012     *   http://www.apache.org/licenses/LICENSE-2.0
013     *
014     * Unless required by applicable law or agreed to in writing,
015     * software distributed under the License is distributed on an
016     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017     * KIND, either express or implied.  See the License for the
018     * specific language governing permissions and limitations
019     * under the License.
020     */
021    
022    import java.text.DateFormat;
023    import java.text.ParseException;
024    
025    import java.util.Date;
026    
027    import org.apache.commons.lang.StringUtils;
028    
029    import org.apache.fulcrum.intake.IntakeException;
030    import org.apache.fulcrum.intake.IntakeRuntimeException;
031    import org.apache.fulcrum.intake.validator.DateStringValidator;
032    import org.apache.fulcrum.intake.xmlmodel.XmlField;
033    
034    
035    /**
036     * Field for date inputs as free form text.  The parsing of date strings
037     * is dependent on any rules that are defined, so this field will expect that
038     * any validator will be (or extend) DateStringValidator.
039     *
040     * @author <a href="mailto:jmcnally@collab.net">John McNally</a>
041     * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
042     * @author <a href="mailto:quintonm@bellsouth.net">Quinton McCombs</a>
043     * @version $Id: DateStringField.java 535465 2007-05-05 06:58:06Z tv $
044     */
045    public class DateStringField
046            extends Field
047    {
048        /** date format */
049        private DateFormat df = null;
050    
051        /**
052         * Constructor.
053         *
054         * @param field xml field definition object
055         * @param group xml group definition object
056         * @throws IntakeException thrown by superclass
057         */
058        public DateStringField(XmlField field, Group group)
059                throws IntakeException
060        {
061            super(field, group);
062    
063            if (validator == null || !(validator instanceof DateStringValidator))
064            {
065                df = DateFormat.getInstance();
066                df.setLenient(true);
067            }
068        }
069    
070        /**
071         * Sets the default value for a DateString field
072         *
073         * @param prop Parameter for the default values
074         */
075        public void setDefaultValue(String prop)
076        {
077            defaultValue = null;
078    
079            if (prop == null)
080            {
081                return;
082            }
083    
084            try
085            {
086                defaultValue = getDate(prop);
087            }
088            catch (ParseException e)
089            {
090                throw new IntakeRuntimeException("Could not parse " + prop
091                        + " into a valid Date for the default value", e);
092            }
093        }
094    
095        /**
096         * Set the empty Value. This value is used if Intake
097         * maps a field to a parameter returned by the user and
098         * the corresponding field is either empty (empty string)
099         * or non-existant.
100         *
101         * @param prop The value to use if the field is empty.
102         */
103        public void setEmptyValue(String prop)
104        {
105            emptyValue = null;
106    
107            if (prop == null)
108            {
109                return;
110            }
111    
112            try
113            {
114                emptyValue = getDate(prop);
115            }
116            catch (ParseException e)
117            {
118                throw new IntakeRuntimeException("Could not parse " + prop
119                        + " into a valid Date for the empty value", e);
120            }
121        }
122    
123        /**
124         * A suitable validator.
125         *
126         * @return "DateStringValidator"
127         */
128        protected String getDefaultValidator()
129        {
130            return DateStringValidator.class.getName();
131        }
132    
133        /**
134         * Sets the value of the field from data in the parser.
135         */
136        protected void doSetValue()
137        {
138            if (isMultiValued)
139            {
140                String[] inputs = parser.getStrings(getKey());
141                Date[] values = new Date[inputs.length];
142                for (int i = 0; i < inputs.length; i++)
143                {
144                    try
145                    {
146                        values[i] = StringUtils.isNotEmpty(inputs[i])
147                                ? getDate(inputs[i]) : (Date) getEmptyValue();
148                    }
149                    catch (ParseException e)
150                    {
151                        values[i] = null;
152                    }
153                }
154                setTestValue(values);
155            }
156            else
157            {
158                String val = parser.getString(getKey());
159                try
160                {
161                    setTestValue(StringUtils.isNotEmpty(val) ? getDate(val) : (Date) getEmptyValue());
162                }
163                catch (ParseException e)
164                {
165                    setTestValue(null);
166                }
167            }
168        }
169    
170        /**
171         * Parses a test date string using the Validator if is exists and
172         * is an instance of DateStringValidator.  Otherwise, DateFormat.parse()
173         * is used.
174         *
175         * @param dateString The string date to parse
176         * @return A <code>Date</code> object
177         * @throws ParseException The date could not be parsed.
178         */
179        private Date getDate(String dateString)
180                throws ParseException
181        {
182            Date date = null;
183            // FIXME: Canonicalize user-entered date strings.
184            if (validator != null && validator instanceof DateStringValidator)
185            {
186                date = ((DateStringValidator) validator).parse(dateString);
187            }
188            else
189            {
190                date = df.parse(dateString);
191            }
192            return date;
193        }
194    
195        /**
196         * returns a String representation
197         *
198         * @return a String representation
199         */
200        public String toString()
201        {
202            String s = null;
203            Object value = getValue();
204            if (value == null)
205            {
206                s = "";
207            }
208            else if (value instanceof String)
209            {
210                s = (String) value;
211            }
212            else if (validator != null && validator instanceof DateStringValidator)
213            {
214                s = ((DateStringValidator) validator).format((Date) value);
215            }
216            else
217            {
218                s = df.format((Date) value);
219            }
220            return s;
221        }
222    }