View Javadoc
1   /*
2    * Copyright (C) 2020 Dipl.-Inform. Kai Hofmann. All rights reserved!
3    */
4   package de.powerstat.validation.values;
5   
6   import java.util.Objects;
7   import java.util.regex.Matcher;
8   import java.util.regex.Pattern;
9   
10  import org.apache.logging.log4j.LogManager;
11  import org.apache.logging.log4j.Logger;
12  
13  /**
14   * Street number.
15   *
16   * Possibly DSGVO relevant.
17   *
18   * TODO optimize constructor/compareTo
19   */
20  public class StreetNr implements Comparable<StreetNr>
21   {
22    /**
23     * Logger.
24     */
25    private static final Logger LOGGER = LogManager.getLogger(StreetNr.class);
26  
27    /**
28     * Regexp for street number formats.
29     */
30    private static final String STREET_NR_REGEXP = "^([0-9]{1,5})((-|/)([0-9]{1,5}))?( ([0-9]{1,3})/([0-9]{1,3}))?( ([a-z]))?$"; //$NON-NLS-1$
31  
32    /**
33     * Maximum known street nr in the world.
34     */
35    private static final int MAX_KNOWN_STREET_NR = 29999;
36  
37    /**
38     * Street number.
39     */
40    private final String streetNr;
41  
42  
43    /**
44     * Constructor.
45     *
46     * @param streetNr Street number
47     * @throws NullPointerException if streetNr is null
48     * @throws IllegalArgumentException if streetNr is not an correct streetNr
49     */
50    public StreetNr(final String streetNr)
51     {
52      super();
53      Objects.requireNonNull(streetNr, "streetNr"); //$NON-NLS-1$
54      if ((streetNr.length() < 1) || (streetNr.length() > 21))
55       {
56        throw new IllegalArgumentException("StreetNr with wrong length"); //$NON-NLS-1$
57       }
58      final Pattern pattern = Pattern.compile(STREET_NR_REGEXP);
59      final Matcher matcher = pattern.matcher(streetNr);
60      if (!matcher.matches())
61       {
62        throw new IllegalArgumentException("StreetNr with wrong format"); //$NON-NLS-1$
63       }
64      // group 1: house nr (from) 42:   42
65      // group 4: house nr (to) 42-43:  43
66      // group 6: numerator 3/4:         3
67      // group 7: denominator 3/4:       4
68      // group 8: alphabetic character:  a
69      if (Integer.parseInt(matcher.group(1)) > MAX_KNOWN_STREET_NR)
70       {
71        throw new IllegalArgumentException("StreetNr > " + MAX_KNOWN_STREET_NR); //$NON-NLS-1$
72       }
73      if ((matcher.group(4) != null) && (Integer.compare(Integer.parseInt(matcher.group(1)), Integer.parseInt(matcher.group(4))) >= 0))
74       {
75        throw new IllegalArgumentException("StreetNr from >= StreetNr to"); //$NON-NLS-1$
76       }
77      if ((matcher.group(7) != null) && (Integer.compare(Integer.parseInt(matcher.group(6)), Integer.parseInt(matcher.group(7))) > 0))
78       {
79        throw new IllegalArgumentException("StreetNr numerator > denominator"); //$NON-NLS-1$
80       }
81      this.streetNr = streetNr;
82     }
83  
84  
85    /**
86     * StreetNr factory.
87     *
88     * @param streetNr StreetNr
89     * @return StreetNr object
90     */
91    public static StreetNr of(final String streetNr)
92     {
93      return new StreetNr(streetNr);
94     }
95  
96  
97    /**
98     * Get streetNr string.
99     *
100    * @return StreetNr string
101    */
102   public String getStreetNr()
103    {
104     return this.streetNr;
105    }
106 
107 
108   /**
109    * Calculate hash code.
110    *
111    * @return Hash
112    * @see java.lang.Object#hashCode()
113    */
114   @Override
115   public int hashCode()
116    {
117     return this.streetNr.hashCode();
118    }
119 
120 
121   /**
122    * Is equal with another object.
123    *
124    * @param obj Object
125    * @return true when equal, false otherwise
126    * @see java.lang.Object#equals(java.lang.Object)
127    */
128   @Override
129   public boolean equals(final Object obj)
130    {
131     if (this == obj)
132      {
133       return true;
134      }
135     if (!(obj instanceof StreetNr))
136      {
137       return false;
138      }
139     final StreetNr./../../../de/powerstat/validation/values/StreetNr.html#StreetNr">StreetNr other = (StreetNr)obj;
140     return this.streetNr.equals(other.streetNr);
141    }
142 
143 
144   /**
145    * Returns the string representation of this StreetNr.
146    *
147    * The exact details of this representation are unspecified and subject to change, but the following may be regarded as typical:
148    *
149    * "StreetNr[streetNr=42]"
150    *
151    * @return String representation of this StreetNr
152    * @see java.lang.Object#toString()
153    */
154   @Override
155   public String toString()
156    {
157     final StringBuilder builder = new StringBuilder(19);
158     builder.append("StreetNr[streetNr=").append(this.streetNr).append(']'); //$NON-NLS-1$
159     return builder.toString();
160    }
161 
162 
163   /**
164    * Compare with another object.
165    *
166    * @param obj Object to compare with
167    * @return 0: equal; 1: greater; -1: smaller
168    * @see java.lang.Comparable#compareTo(java.lang.Object)
169    */
170   @Override
171   public int compareTo(final StreetNr obj)
172    {
173     Objects.requireNonNull(obj, "obj"); //$NON-NLS-1$
174     final Pattern pattern = Pattern.compile(STREET_NR_REGEXP);
175     final Matcher matcher1 = pattern.matcher(this.streetNr);
176     final Matcher matcher2 = pattern.matcher(obj.streetNr);
177     if (!matcher1.matches() || !matcher2.matches())
178      {
179       throw new IllegalStateException("One or both of the two streetNr objects does not match the streetNr pattern"); //$NON-NLS-1$
180      }
181     // group 1: house nr (from) 42:   42
182     // group 4: house nr (to) 42-43:  43
183     // group 6: numerator 3/4:         3
184     // group 7: denominator 3/4:       4
185     // group 8: alphabetic character:  a
186     int result = Integer.compare(Integer.parseInt(matcher1.group(1)), Integer.parseInt(matcher2.group(1)));
187     if (result == 0)
188      {
189       if ((matcher1.group(7) != null) || (matcher2.group(7) != null)) // 3/4
190        {
191         if (matcher1.group(7) == null)
192          {
193           return -1;
194          }
195         else if (matcher2.group(7) == null)
196          {
197           return 1;
198          }
199         else
200          {
201           if (matcher1.group(7).compareTo(matcher2.group(7)) != 0)
202            {
203             throw new IllegalStateException("StreetNrs do not have the same denominator"); //$NON-NLS-1$
204            }
205           result = Integer.compare(Integer.parseInt(matcher1.group(6)), Integer.parseInt(matcher2.group(6)));
206           if (result != 0)
207            {
208             return result;
209            }
210          }
211        }
212       if ((matcher1.group(8) != null) || (matcher2.group(8) != null)) // a-z
213        {
214         if (matcher1.group(8) == null)
215          {
216           result = -1;
217          }
218         else if (matcher2.group(8) == null)
219          {
220           result = 1;
221          }
222         else
223          {
224           result = matcher1.group(8).compareTo(matcher2.group(8));
225          }
226        }
227      }
228     return result;
229    }
230 
231  }