001/*
002 * Copyright 2017-2020 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2017-2020 Ping Identity Corporation
007 *
008 * Licensed under the Apache License, Version 2.0 (the "License");
009 * you may not use this file except in compliance with the License.
010 * 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, software
015 * distributed under the License is distributed on an "AS IS" BASIS,
016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017 * See the License for the specific language governing permissions and
018 * limitations under the License.
019 */
020/*
021 * Copyright (C) 2017-2020 Ping Identity Corporation
022 *
023 * This program is free software; you can redistribute it and/or modify
024 * it under the terms of the GNU General Public License (GPLv2 only)
025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
026 * as published by the Free Software Foundation.
027 *
028 * This program is distributed in the hope that it will be useful,
029 * but WITHOUT ANY WARRANTY; without even the implied warranty of
030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
031 * GNU General Public License for more details.
032 *
033 * You should have received a copy of the GNU General Public License
034 * along with this program; if not, see <http://www.gnu.org/licenses>.
035 */
036package com.unboundid.util.args;
037
038
039
040import java.io.Serializable;
041import java.util.List;
042
043import com.unboundid.util.NotMutable;
044import com.unboundid.util.OID;
045import com.unboundid.util.ThreadSafety;
046import com.unboundid.util.ThreadSafetyLevel;
047
048import static com.unboundid.util.args.ArgsMessages.*;
049
050
051
052/**
053 * This class provides an implementation of an argument value validator that
054 * ensures that values can be parsed as valid object identifiers.
055 */
056@NotMutable()
057@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
058public final class OIDArgumentValueValidator
059       extends ArgumentValueValidator
060       implements Serializable
061{
062  /**
063   * The serial version UID for this serializable class.
064   */
065  private static final long serialVersionUID = 2195078137238476902L;
066
067
068
069  // Indicates whether to perform strict validation.
070  private final boolean isStrict;
071
072
073
074  /**
075   * Creates a new OID address argument value validator that will only accept
076   * strictly valid numeric OIDs.
077   */
078  public OIDArgumentValueValidator()
079  {
080    this(true);
081  }
082
083
084
085  /**
086   * Creates a new OID address argument value validator that will only accept
087   * valid numeric OIDs.
088   *
089   * @param  isStrict  Indicates whether to perform strict validation.  If this
090   *                   is {@code false}, then the validator will only sure that
091   *                   each value is a dotted list of digits that does not start
092   *                   or end with a period and does not contain two consecutive
093   *                   periods.  If this is {@code true}, then it will also
094   *                   ensure that it contains at least two components, that the
095   *                   value of the first component is not greater than two,
096   *                   and that the value of the second component is not greater
097   *                   than 39 if the value of the first component is zero or
098   *                   one.
099   */
100  public OIDArgumentValueValidator(final boolean isStrict)
101  {
102    this.isStrict = isStrict;
103  }
104
105
106
107  /**
108   * Indicates whether this validator is configured to operate in strict mode.
109   * If it not operating in strict mode, then it will only ensure that each
110   * value is is a dotted list of digits that does not start or end with a
111   * period and does not contain two consecutive periods.  If it is strict, then
112   * it will also ensure that it contains at least two components, that the
113   * value of the first component is not greater than two, and that the value of
114   * the second component is not greater than 39 if the value of the first
115   * component is zero or one.
116   *
117   * @return  {@code true} if this validator is configured to operate in strict
118   *          mode, or {@code false} if not.
119   */
120  public boolean isStrict()
121  {
122    return isStrict;
123  }
124
125
126
127  /**
128   * {@inheritDoc}
129   */
130  @Override()
131  public void validateArgumentValue(final Argument argument,
132                                    final String valueString)
133         throws ArgumentException
134  {
135    if (valueString.isEmpty())
136    {
137      throw new ArgumentException(ERR_OID_VALIDATOR_EMPTY.get(valueString,
138           argument.getIdentifierString()));
139    }
140
141    if (valueString.startsWith(".") || valueString.endsWith("."))
142    {
143      throw new ArgumentException(
144           ERR_OID_VALIDATOR_STARTS_OR_ENDS_WITH_PERIOD.get(valueString,
145                argument.getIdentifierString()));
146    }
147
148    if (valueString.contains(".."))
149    {
150      throw new ArgumentException(
151           ERR_OID_VALIDATOR_CONSECUTIVE_PERIODS.get(valueString,
152                argument.getIdentifierString()));
153    }
154
155    final OID oid = new OID(valueString);
156    if (! oid.isValidNumericOID())
157    {
158      throw new ArgumentException(
159           ERR_OID_VALIDATOR_ILLEGAL_CHARACTER.get(valueString,
160                argument.getIdentifierString()));
161    }
162
163    if (! isStrict)
164    {
165      return;
166    }
167
168    final List<Integer> components = oid.getComponents();
169    if (components.size() < 2)
170    {
171      throw new ArgumentException(
172           ERR_OID_VALIDATOR_NOT_ENOUGH_COMPONENTS.get(valueString,
173                argument.getIdentifierString()));
174    }
175
176    final int firstComponent = components.get(0);
177    final int secondComponent = components.get(1);
178    switch (firstComponent)
179    {
180      case 0:
181      case 1:
182        if (secondComponent > 39)
183        {
184          throw new ArgumentException(
185               ERR_OID_VALIDATOR_ILLEGAL_SECOND_COMPONENT.get(valueString,
186                    argument.getIdentifierString()));
187        }
188        break;
189
190      case 2:
191        // We don't need to do any more validation.
192        break;
193
194      default:
195        // Invalid value for the first component.
196        throw new ArgumentException(
197             ERR_OID_VALIDATOR_ILLEGAL_FIRST_COMPONENT.get(valueString,
198                  argument.getIdentifierString()));
199    }
200  }
201
202
203
204  /**
205   * Retrieves a string representation of this argument value validator.
206   *
207   * @return  A string representation of this argument value validator.
208   */
209  @Override()
210  public String toString()
211  {
212    final StringBuilder buffer = new StringBuilder();
213    toString(buffer);
214    return buffer.toString();
215  }
216
217
218
219  /**
220   * Appends a string representation of this argument value validator to the
221   * provided buffer.
222   *
223   * @param  buffer  The buffer to which the string representation should be
224   *                 appended.
225   */
226  public void toString(final StringBuilder buffer)
227  {
228    buffer.append("OIDArgumentValueValidator(isStrict=");
229    buffer.append(isStrict);
230    buffer.append(')');
231  }
232}