• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Libphonenumber Authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.google.i18n.phonenumbers.metadata.table;
17 
18 import static com.google.common.base.Preconditions.checkArgument;
19 import static com.google.common.base.Preconditions.checkNotNull;
20 import static java.util.stream.Collectors.joining;
21 
22 import com.google.i18n.phonenumbers.metadata.RangeTree;
23 import com.google.i18n.phonenumbers.metadata.table.RangeTable.OverwriteMode;
24 import javax.annotation.Nullable;
25 
26 /** A structured exception which should be used whenever structural errors occur in table data. */
27 public final class RangeException extends IllegalArgumentException {
28   // Called when assigning ranges, depending on the overwrite mode. As more cases are added,
29   // consider refactoring and subclassing for clean semantics.
checkDisjoint( Column<T> column, T value, RangeTree existing, RangeTree ranges, OverwriteMode mode)30   static <T extends Comparable<T>> void checkDisjoint(
31       Column<T> column, T value, RangeTree existing, RangeTree ranges, OverwriteMode mode) {
32     RangeTree intersection = existing.intersect(ranges);
33     if (!intersection.isEmpty()) {
34       // A non-empty intersection implies both inputs are also non-empty.
35       throw new RangeException(column, value, existing, ranges, intersection, mode);
36     }
37   }
38 
RangeException(Column<?> column, @Nullable Object value, RangeTree existing, RangeTree ranges, RangeTree intersection, OverwriteMode mode)39   RangeException(Column<?> column,
40       @Nullable Object value,
41       RangeTree existing,
42       RangeTree ranges,
43       RangeTree intersection,
44       OverwriteMode mode) {
45     super(explain(checkNotNull(column), value, existing, ranges, intersection, checkNotNull(mode)));
46   }
47 
explain( Column<?> column, @Nullable Object value, RangeTree existing, RangeTree ranges, RangeTree intersection, OverwriteMode mode)48   private static String explain(
49       Column<?> column,
50       @Nullable Object value,
51       RangeTree existing,
52       RangeTree ranges,
53       RangeTree intersection,
54       OverwriteMode mode) {
55     return String.format(
56         "cannot assign non-disjoint ranges for value '%s' in column '%s' using overwrite mode: %s\n"
57             + "overlapping ranges:\n%s"
58             + "existing ranges:\n%s"
59             + "new ranges:\n%s",
60         value, column, mode, toLines(intersection), toLines(existing), toLines(ranges));
61   }
62 
toLines(RangeTree ranges)63   private static String toLines(RangeTree ranges) {
64     checkArgument(!ranges.isEmpty());
65     return ranges.asRangeSpecifications().stream().map(s -> "  " + s + "\n").collect(joining());
66   }
67 
68   // We suppress stack traces for "semantic" exceptions, since these aren't intended to indicate
69   // bugs, but rather user error (for which a stack trace is not very useful).
70   @Override
fillInStackTrace()71   public synchronized Throwable fillInStackTrace() {
72     return this;
73   }
74 }
75