| Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
| NumericalValue |
|
| 3.2;3.2 |
| 1 | package org.jscsi.target.settings; | |
| 2 | ||
| 3 | ||
| 4 | import java.util.regex.Matcher; | |
| 5 | import java.util.regex.Pattern; | |
| 6 | ||
| 7 | ||
| 8 | /** | |
| 9 | * An abstract parent class to {@link SingleNumericalValue} and {@link NumericalValueRange}. Objects of these two | |
| 10 | * classes represent single integers and integer intervals, respectively, and can be parsed from any properly formatted | |
| 11 | * <i>key=value</i> pair <i>value</i>, be they formatted in decimal, hexadecimal, or Base64 notation. | |
| 12 | * <p> | |
| 13 | * Instances of {@link NumericalValue} can be intersected, i.e. that by using either the | |
| 14 | * {@link #intersect(NumericalValue)} or the {@link #intersect(NumericalValue, NumericalValue)}, a | |
| 15 | * {@link NumericalValue} can be created which encompasses all integers that are part of the range of values represented | |
| 16 | * by the intersected {@link NumericalValue} objects. | |
| 17 | * <p> | |
| 18 | * For example, if the interval [1,10] is intersected with the interval [5,15], the result would be a | |
| 19 | * {@link NumericalValueRange} representing the interval [5,10]. Intersecting an interval with a single number would | |
| 20 | * return the number, but only if the number is part of the interval. Generally, both methods return <code>null</code> | |
| 21 | * if there is no overlap. | |
| 22 | * | |
| 23 | * @author Andreas Ergenzinger | |
| 24 | */ | |
| 25 | 0 | public abstract class NumericalValue { |
| 26 | ||
| 27 | // *** single number regular expressions *** | |
| 28 | /** | |
| 29 | * Regular expression for decimal integers. | |
| 30 | */ | |
| 31 | private static final String DECIMAL_REGEX = "0|[-]?[1-9][0-9]*"; | |
| 32 | ||
| 33 | /** | |
| 34 | * Regular expression for hexadecimal integers. | |
| 35 | */ | |
| 36 | private static final String HEX_REGEX = "0[x|X][0-9a-fA-F]+"; | |
| 37 | ||
| 38 | /** | |
| 39 | * Regular expression for Base64 integers. | |
| 40 | */ | |
| 41 | private static final String BASE_64_REGEX = "0[b|B][0-9a-zA-Z+/]+"; | |
| 42 | private static final String SINGLE_CONSTANT_REGEX = DECIMAL_REGEX + "|" + HEX_REGEX + "|" + BASE_64_REGEX; | |
| 43 | ||
| 44 | // *** single number patterns *** | |
| 45 | /** | |
| 46 | * A precompiled pattern for matching decimal integer {@link String}. | |
| 47 | */ | |
| 48 | 0 | public static final Pattern DECIMAL_CONSTANT_PATTERN = Pattern.compile(DECIMAL_REGEX); |
| 49 | ||
| 50 | /** | |
| 51 | * A precompiled pattern for matching hexadecimal integer {@link String}. | |
| 52 | */ | |
| 53 | 0 | public static final Pattern HEX_CONSTANT_PATTERN = Pattern.compile(HEX_REGEX); |
| 54 | ||
| 55 | /** | |
| 56 | * A precompiled pattern for matching Base64 integer {@link String}. | |
| 57 | */ | |
| 58 | 0 | public static final Pattern BASE_64_CONSTANT_PATTERN = Pattern.compile(BASE_64_REGEX); |
| 59 | ||
| 60 | /** | |
| 61 | * A precompiled pattern for matching decimal, hexadecimal, and Base64 integer {@link String}. | |
| 62 | */ | |
| 63 | 0 | public static final Pattern SINGLE_CONSTANT_PATTERN = Pattern.compile(SINGLE_CONSTANT_REGEX); |
| 64 | ||
| 65 | /** | |
| 66 | * A precompiled pattern for matching decimal, hexadecimal, and Base64 integer interval {@link String} (two integers | |
| 67 | * separated by '~'). | |
| 68 | */ | |
| 69 | 0 | public static final Pattern NUMERICAL_RANGE_PATTERN = Pattern.compile("(" + SINGLE_CONSTANT_REGEX + ")~(" + SINGLE_CONSTANT_REGEX + ")"); |
| 70 | ||
| 71 | // *** methods *** | |
| 72 | ||
| 73 | /** | |
| 74 | * Parses a {@link NumericalValue} from a {@link String}. | |
| 75 | * | |
| 76 | * @param value the {@link String} to parse. | |
| 77 | * @return a {@link NumericalValue} or <code>null</code> if the parameter does not match any of the supported | |
| 78 | * patterns (specified by the iSCSI standard). | |
| 79 | */ | |
| 80 | public static final NumericalValue parseNumericalValue (final String value) { | |
| 81 | // return SingleNumericalValue ... | |
| 82 | 0 | final Matcher singleValueMatcher = SINGLE_CONSTANT_PATTERN.matcher(value); |
| 83 | 0 | if (singleValueMatcher.matches()) return SingleNumericalValue.parseSingleNumericValue(value); |
| 84 | // ... NumericalValueRange ... | |
| 85 | 0 | final Matcher rangeMatcher = NUMERICAL_RANGE_PATTERN.matcher(value); |
| 86 | 0 | if (rangeMatcher.matches()) return NumericalValueRange.parseNumericalValueRange(value); |
| 87 | // ... or null | |
| 88 | 0 | return null; |
| 89 | } | |
| 90 | ||
| 91 | /** | |
| 92 | * Returns a {@link NumericalValue} spanning the overlap of this {@link NumericalValue} and the parameter. | |
| 93 | * | |
| 94 | * @param value the {@link NumericalValue} to be intersected with this object | |
| 95 | * @return a {@link NumericalValue} representing the intersection of this {@link NumericalValue} with the parameter | |
| 96 | */ | |
| 97 | public NumericalValue intersect (final NumericalValue value) { | |
| 98 | 0 | return intersect(this, value); |
| 99 | } | |
| 100 | ||
| 101 | /** | |
| 102 | * Returns a {@link NumericalValue} representing the intersection of the two parameters | |
| 103 | * | |
| 104 | * @param a the first {@link NumericalValue} | |
| 105 | * @param b the second {@link NumericalValue} | |
| 106 | * @return a {@link NumericalValue} representing the intersection of the two parameters | |
| 107 | */ | |
| 108 | public static NumericalValue intersect (final NumericalValue a, final NumericalValue b) { | |
| 109 | // early exit | |
| 110 | 0 | if (a == null || b == null) return null; |
| 111 | // get ranges of a and b | |
| 112 | int aMin, aMax, bMin, bMax; | |
| 113 | 0 | if (a instanceof SingleNumericalValue) { |
| 114 | 0 | final SingleNumericalValue v = (SingleNumericalValue) a; |
| 115 | 0 | aMin = v.getValue(); |
| 116 | 0 | aMax = aMin; |
| 117 | 0 | } else { |
| 118 | 0 | final NumericalValueRange r = (NumericalValueRange) a; |
| 119 | 0 | aMin = r.getMin(); |
| 120 | 0 | aMax = r.getMax(); |
| 121 | } | |
| 122 | 0 | if (b instanceof SingleNumericalValue) { |
| 123 | 0 | final SingleNumericalValue v = (SingleNumericalValue) b; |
| 124 | 0 | bMin = v.getValue(); |
| 125 | 0 | bMax = bMin; |
| 126 | 0 | } else { |
| 127 | 0 | final NumericalValueRange r = (NumericalValueRange) b; |
| 128 | 0 | bMin = r.getMin(); |
| 129 | 0 | bMax = r.getMax(); |
| 130 | } | |
| 131 | // intersect ranges | |
| 132 | 0 | final int min = Math.max(aMin, bMin); |
| 133 | 0 | final int max = Math.min(aMax, bMax); |
| 134 | 0 | if (min == max) |
| 135 | 0 | return SingleNumericalValue.create(min); |
| 136 | else | |
| 137 | 0 | return NumericalValueRange.create(min, max); |
| 138 | } | |
| 139 | ||
| 140 | /** | |
| 141 | * Returns true if the passed {@link Integer} or {@link NumericalValue} lies completely inside the interval | |
| 142 | * represented by this {@link NumericalValue} . If the parameter is not an {@link Integer} or a | |
| 143 | * {@link NumericalValue}, the method will return <code>false</code>. | |
| 144 | * | |
| 145 | * @param value the {@link Integer} or {@link NumericalValue} to check | |
| 146 | * @return <code>true</code> if the value is complete contained, <code>false</code> if it is not | |
| 147 | */ | |
| 148 | public abstract boolean contains (Object value); | |
| 149 | ||
| 150 | /** | |
| 151 | * Returns true if the passed integer lies completely inside the interval represented by this {@link NumericalValue} | |
| 152 | * . | |
| 153 | * | |
| 154 | * @param value the integer to check | |
| 155 | * @return <code>true</code> if the value is complete contained, <code>false</code> if it is not | |
| 156 | */ | |
| 157 | public abstract boolean contains (int value); | |
| 158 | } |