org.apache.ws.security.util.XmlSchemaDateFormat Maven / Gradle / Ivy
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 {@link DateFormat} for the format of the dateTime simpleType as specified in the
* XML Schema specification. See
* XML Schema Part 2: Datatypes, W3C Recommendation 02 May 2001, Section 3.2.7.1.
*
* @author Ian P. Springer
* @author Werner Dittmann
*/
public class XmlSchemaDateFormat extends DateFormat {
/**
* Logger.
*/
private static Log log = LogFactory.getLog(XmlSchemaDateFormat.class);
/**
* 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 org.apache.axis.encoding.ser.CalendarDeserializer,
* 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(), pe);
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: " + error_reason,
parse_pos.getErrorIndex()
);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy