werner      2005/05/01 11:21:17

  Added:       wss4j/src/org/apache/ws/security/util
                        XmlSchemaDateFormat.java
  Log:
  New class to process XML Schema compliant timestamps.
  Thanks to Ian. P. Springer for the code.
  
  Revision  Changes    Path
  1.1                  
ws-fx/wss4j/src/org/apache/ws/security/util/XmlSchemaDateFormat.java
  
  Index: XmlSchemaDateFormat.java
  ===================================================================
  /*
   * Copyright  2003-2005 The Apache Software Foundation.
   *
   *  Licensed under the Apache License, Version 2.0 (the "License");
   *  you may not use this file except in compliance with the License.
   *  You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   *  Unless required by applicable law or agreed to in writing, software
   *  distributed under the License is distributed on an "AS IS" BASIS,
   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   *  See the License for the specific language governing permissions and
   *  limitations under the License.
   *
   */
  
  package org.apache.ws.security.util;
  
  import java.text.DateFormat;
  import java.text.FieldPosition;
  import java.text.ParsePosition;
  import java.text.SimpleDateFormat;
  import java.text.ParseException;
  import java.util.Date;
  import java.util.TimeZone;
  
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogFactory;
  
  /**
   * A [EMAIL PROTECTED] DateFormat} for the format of the dateTime simpleType 
as specified in the
   * XML Schema specification. See <a 
href="http://www.w3.org/TR/xmlschema-2/#dateTime";>
   * XML Schema Part 2: Datatypes, W3C Recommendation 02 May 2001, Section 
3.2.7.1</a>.
   *
   * @author Ian P. Springer
   * @author Werner Dittmann
   */
  public class XmlSchemaDateFormat extends DateFormat {
        /**
         * Logger.
         */
        private static Log log = LogFactory.getLog(XmlSchemaDateFormat.class);
  
        private static boolean doDebug = false;
  
        static {
                doDebug = log.isDebugEnabled();
        }
  
        /**
         * Message retriever.
         */
        //   private static final MessageRetriever MSG = ResourceKeys.MSG;
        /**
         * DateFormat for Zulu (UTC) form of an XML Schema dateTime string.
         */
        private static final DateFormat DATEFORMAT_XSD_ZULU = new 
SimpleDateFormat(
                        "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
  
        static {
                DATEFORMAT_XSD_ZULU.setTimeZone(TimeZone.getTimeZone("UTC"));
        }
  
        /**
         * This method was snarfed from 
<tt>org.apache.axis.encoding.ser.CalendarDeserializer</tt>,
         * which was written by Sam Ruby ([EMAIL PROTECTED]) and Rich Scheuerle 
([EMAIL PROTECTED]).
         * Better error reporting was added.
         *
         * @see DateFormat#parse(java.lang.String)
         */
        public Date parse(String src, ParsePosition parse_pos) {
                Date date;
  
                // validate fixed portion of format
                int index = 0;
                try {
                        if (src != null) {
                                if ((src.charAt(0) == '+') || (src.charAt(0) == 
'-')) {
                                        src = src.substring(1);
                                }
  
                                if (src.length() < 19) {
                                        parse_pos.setIndex(src.length() - 1);
                                        handleParseError(parse_pos, 
"TOO_FEW_CHARS");
                                }
                                validateChar(src, parse_pos, index = 4, '-', 
"EXPECTED_DASH");
                                validateChar(src, parse_pos, index = 7, '-', 
"EXPECTED_DASH");
                                validateChar(src, parse_pos, index = 10, 'T', 
"EXPECTED_CAPITAL_T");
                                validateChar(src, parse_pos, index = 13, ':', 
"EXPECTED_COLON_IN_TIME");
                                validateChar(src, parse_pos, index = 16, ':', 
"EXPECTED_COLON_IN_TIME");
                        }
  
                        // convert what we have validated so far
                        try {
                                synchronized (DATEFORMAT_XSD_ZULU) {
                                        date = DATEFORMAT_XSD_ZULU.parse((src 
== null) ? null
                                                        : (src.substring(0, 19) 
+ ".000Z"));
                                }
                        } catch (Exception e) {
                                throw new NumberFormatException(e.toString());
                        }
  
                        index = 19;
  
                        // parse optional milliseconds
                        if (src != null) {
                                if ((index < src.length()) && 
(src.charAt(index) == '.')) {
                                        int milliseconds = 0;
                                        int start = ++index;
  
                                        while ((index < src.length())
                                                        && 
Character.isDigit(src.charAt(index))) {
                                                index++;
                                        }
  
                                        String decimal = src.substring(start, 
index);
  
                                        if (decimal.length() == 3) {
                                                milliseconds = 
Integer.parseInt(decimal);
                                        } else if (decimal.length() < 3) {
                                                milliseconds = 
Integer.parseInt((decimal + "000")
                                                                .substring(0, 
3));
                                        } else {
                                                milliseconds = Integer
                                                                
.parseInt(decimal.substring(0, 3));
  
                                                if (decimal.charAt(3) >= '5') {
                                                        ++milliseconds;
                                                }
                                        }
  
                                        // add milliseconds to the current date
                                        date.setTime(date.getTime() + 
milliseconds);
                                }
  
                                // parse optional timezone
                                if (((index + 5) < src.length())
                                                && ((src.charAt(index) == '+') 
|| (src.charAt(index) == '-'))) {
                                        validateCharIsDigit(src, parse_pos, 
index + 1, "EXPECTED_NUMERAL");
                                        validateCharIsDigit(src, parse_pos, 
index + 2, "EXPECTED_NUMERAL");
                                        validateChar(src, parse_pos, index + 3, 
':', "EXPECTED_COLON_IN_TIMEZONE");
                                        validateCharIsDigit(src, parse_pos, 
index + 4, "EXPECTED_NUMERAL");
                                        validateCharIsDigit(src, parse_pos, 
index + 5, "EXPECTED_NUMERAL");
  
                                        final int hours = (((src.charAt(index + 
1) - '0') * 10) + src
                                                        .charAt(index + 2)) - 
'0';
                                        final int mins = (((src.charAt(index + 
4) - '0') * 10) + src
                                                        .charAt(index + 5)) - 
'0';
                                        int millisecs = ((hours * 60) + mins) * 
60 * 1000;
  
                                        // subtract millisecs from current date 
to obtain GMT
                                        if (src.charAt(index) == '+') {
                                                millisecs = -millisecs;
                                        }
  
                                        date.setTime(date.getTime() + 
millisecs);
                                        index += 6;
                                }
  
                                if ((index < src.length()) && 
(src.charAt(index) == 'Z')) {
                                        index++;
                                }
  
                                if (index < src.length()) {
                                        handleParseError(parse_pos, 
"TOO_MANY_CHARS");
                                }
                        }
                } catch (ParseException pe) {
                        log.error(pe.toString());
                        index = 0; // IMPORTANT: this tells DateFormat.parse() 
to throw a ParseException
                        parse_pos.setErrorIndex(index);
                        date = null;
                }
                parse_pos.setIndex(index);
                return (date);
        }
  
        /**
         * @see DateFormat#format(java.util.Date)
         */
        public StringBuffer format(Date date, StringBuffer append_buf,
                        FieldPosition field_pos) {
                String str;
  
                synchronized (DATEFORMAT_XSD_ZULU) {
                        str = DATEFORMAT_XSD_ZULU.format(date);
                }
  
                if (append_buf == null) {
                        append_buf = new StringBuffer();
                }
  
                append_buf.append(str);
  
                return (append_buf);
        }
  
        private void validateChar(String str, ParsePosition parse_pos, int 
index,
                        char expected, String error_reason) throws 
ParseException {
                if (str.charAt(index) != expected) {
                        handleParseError(parse_pos, error_reason);
                }
        }
  
        private void validateCharIsDigit(String str, ParsePosition parse_pos,
                        int index, String error_reason) throws ParseException {
                if (!Character.isDigit(str.charAt(index))) {
                        handleParseError(parse_pos, error_reason);
                }
        }
  
        private void handleParseError(ParsePosition parse_pos, String 
error_reason)
                        throws ParseException {
                throw new ParseException("INVALID_XSD_DATETIME", 
parse_pos.getErrorIndex());
        }
  
  }
  
  

Reply via email to