001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.directory.api.ldap.model.schema.syntaxCheckers; 021 022 023import java.util.regex.Pattern; 024 025import org.apache.directory.api.ldap.model.constants.SchemaConstants; 026import org.apache.directory.api.ldap.model.schema.SyntaxChecker; 027import org.apache.directory.api.util.Strings; 028import org.slf4j.Logger; 029import org.slf4j.LoggerFactory; 030 031 032/** 033 * A SyntaxChecker which verifies that a value is a generalized time 034 * according to RFC 4517. 035 * 036 * From RFC 4517 : 037 * GeneralizedTime = century year month day hour 038 * [ minute [ second / leap-second ] ] 039 * [ fraction ] 040 * g-time-zone 041 * 042 * century = 2(%x30-39) ; "00" to "99" 043 * year = 2(%x30-39) ; "00" to "99" 044 * month = ( %x30 %x31-39 ) ; "01" (January) to "09" 045 * | ( %x31 %x30-32 ) ; "10" to "12" 046 * day = ( %x30 %x31-39 ) ; "01" to "09" 047 * | ( %x31-32 %x30-39 ) ; "10" to "29" 048 * | ( %x33 %x30-31 ) ; "30" to "31" 049 * hour = ( %x30-31 %x30-39 ) 050 * | ( %x32 %x30-33 ) ; "00" to "23" 051 * minute = %x30-35 %x30-39 ; "00" to "59" 052 * 053 * second = ( %x30-35 %x30-39 ) ; "00" to "59" 054 * leap-second = ( %x36 %x30 ) ; "60" 055 * 056 * fraction = ( DOT / COMMA ) 1*(%x30-39) 057 * g-time-zone = %x5A ; "Z" 058 * | g-differential 059 * g-differential = ( MINUS / PLUS ) hour [ minute ] 060 * MINUS = %x2D ; minus sign ("-") 061 * 062 * From RFC 4512 : 063 * PLUS = %x2B ; plus sign ("+") 064 * DOT = %x2E ; period (".") 065 * COMMA = %x2C ; comma (",") 066 * 067 * 068 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 069 */ 070@SuppressWarnings("serial") 071public class GeneralizedTimeSyntaxChecker extends SyntaxChecker 072{ 073 /** A logger for this class */ 074 private static final Logger LOG = LoggerFactory.getLogger( GeneralizedTimeSyntaxChecker.class ); 075 076 /** The GeneralizedDate pattern matching */ 077 private static final String GENERALIZED_TIME_PATTERN = 078 "^\\d{4}" // century + year : 0000 to 9999 079 + "(0[1-9]|1[0-2])" // month : 01 to 12 080 + "(0[1-9]|[12]\\d|3[01])" // day : 01 to 31 081 + "([01]\\d|2[0-3])" // hour : 00 to 23 082 + "(" 083 + "([0-5]\\d)" // optional minute : 00 to 59 084 + "([0-5]\\d|60)?" // optional second | leap second 085 + ")?" 086 + "([.,]\\d+)?" // fraction 087 + "(Z|[+-]([01]\\d|2[0-3])([0-5]\\d)?)$"; // time-zone 088 089 /** The date pattern. The regexp pattern is immutable, only one instance needed. */ 090 private static final Pattern DATE_PATTERN = Pattern.compile( GENERALIZED_TIME_PATTERN ); 091 092 093 /** 094 * Creates a new instance of GeneralizedTimeSyntaxChecker. 095 */ 096 public GeneralizedTimeSyntaxChecker() 097 { 098 super( SchemaConstants.GENERALIZED_TIME_SYNTAX ); 099 } 100 101 102 /** 103 * {@inheritDoc} 104 */ 105 public boolean isValidSyntax( Object value ) 106 { 107 String strValue = null; 108 109 if ( value == null ) 110 { 111 LOG.debug( "Syntax invalid for 'null'" ); 112 return false; 113 } 114 115 if ( value instanceof String ) 116 { 117 strValue = ( String ) value; 118 } 119 else if ( value instanceof byte[] ) 120 { 121 strValue = Strings.utf8ToString( ( byte[] ) value ); 122 } 123 else 124 { 125 strValue = value.toString(); 126 } 127 128 // A generalized time must have a minimal length of 11 129 if ( strValue.length() < 11 ) 130 { 131 LOG.debug( "Syntax invalid for '{}'", value ); 132 return false; 133 } 134 135 // Start the date parsing 136 boolean result = DATE_PATTERN.matcher( strValue ).find(); 137 138 if ( result ) 139 { 140 LOG.debug( "Syntax valid for '{}'", value ); 141 } 142 else 143 { 144 LOG.debug( "Syntax invalid for '{}'", value ); 145 } 146 147 return result; 148 } 149}