View Javadoc
1   package org.example.customer;
2   
3   /*
4    * This is free and unencumbered software released into the public domain.
5    * Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software,
6    * either in source code form or as a compiled binary, for any purpose, commercial or
7    * non-commercial, and by any means.
8    *
9    * In jurisdictions that recognize copyright laws, the author or authors of this
10   * software dedicate any and all copyright interest in the software to the public domain.
11   * We make this dedication for the benefit of the public at large and to the detriment of
12   * our heirs and successors. We intend this dedication to be an overt act of relinquishment in
13   * perpetuity of all present and future rights to this software under copyright law.
14   *
15   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
16   * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
17   * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES
18   * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20   *
21   * For more information, please refer to: https://unlicense.org/
22  */
23  
24  import java.io.Serializable;
25  
26  import org.apache.commons.lang3.builder.EqualsBuilder;
27  import org.apache.commons.lang3.builder.HashCodeBuilder;
28  import org.apache.logging.log4j.LogManager;
29  import org.apache.logging.log4j.Logger;
30  import org.example.customer.utility.CustomerEntity;
31  import org.example.customer.utility.Location;
32  import org.example.customer.utility.Phone;
33  import org.example.websecurity.XssSanitizer;
34  import org.example.websecurity.XssSanitizerImpl;
35  
36  /**
37   * The Customer Entity for the Customer application.
38   * <br>
39   * <br>
40   * This class represents the following DB Table:
41   *
42   * <pre>
43   * CREATE TABLE CUSTOMER (
44   *      ID INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1),
45   *      FIRST_NAME VARCHAR(40) NOT NULL,
46   *      LAST_NAME VARCHAR(40) NOT NULL,
47   *      CITY VARCHAR(40),
48   *      COUNTRY VARCHAR(40),
49   *      PHONE VARCHAR(20),
50   *      CONSTRAINT PK_CUSTOMER PRIMARY KEY (ID)
51   *   );
52   * </pre>
53   *
54   * @author Jonathan Earl
55   * @version 1.0
56   *
57   */
58  public final class Customer extends CustomerEntity
59      implements Serializable, Comparable<Customer>
60  {
61      private static final long serialVersionUID = 1L;
62  
63      private static final Logger LOG = LogManager.getLogger();
64  
65      private String myFirstName;
66      private String myLastName;
67      private Location myLocation;
68      private Phone myPhone;
69  
70      private XssSanitizer mySanitizer;
71  
72      /**
73       * The default constructor for the Customer class.
74       * <p>
75       * The initial values are:
76       * <ul>
77       *   <li>id: 1</li>
78       *   <li>first name: John</li>
79       *   <li>last name: Smith</li>
80       *   <li>city: New York City</li>
81       *   <li>country: United States of America</li>
82       *   <li>phone: null</li>
83       * </ul>
84       */
85      public Customer()
86      {
87          this(new XssSanitizerImpl());
88          LOG.debug("Finishing the default Constructor");
89      }
90  
91      /**
92       * The overloaded constructor for the Customer class that takes an XssSanitizer as input.
93       * <p>
94       * The initial values are:
95       * <ul>
96       *   <li>id: 1</li>
97       *   <li>first name: John</li>
98       *   <li>last name: Smith</li>
99       *   <li>city: New York City</li>
100      *   <li>country: United States of America</li>
101      *   <li>phone: null</li>
102      * </ul>
103      *
104      * @param sanitizer the XssSanitizer used by this instance
105      */
106     public Customer(final XssSanitizer sanitizer)
107     {
108         LOG.debug("Starting the overloaded Constructor");
109         final int initialId = 1;
110         final String initialFirstName = "John";
111         final String initialLastName = "Smith";
112         final String initialNumber = null;
113 
114         mySanitizer = sanitizer;
115 
116         setId(initialId);
117         setFirstName(initialFirstName);
118         setLastName(initialLastName);
119         setLocation(new Location());
120         Phone temp2 = new Phone();
121         temp2.setNumber(initialNumber);
122         setPhone(temp2);
123     }
124 
125     /**
126      * This will enable sorting of Customers by full name.
127      * <br>
128      * <br>
129      * @param other the Customer object to compare with
130      * @return the sort value of negative/zero/positive
131      */
132     @Override
133     public int compareTo(Customer other)
134     {
135         String thisFullName = this.getFirstName() + " " 
136                 + this.getLastName();
137         String otherFullName = other.getFirstName() + " " 
138                 + other.getLastName();
139         return thisFullName.compareToIgnoreCase(otherFullName);
140     }
141 
142     /**
143      * Returns the first name value for the Customer.
144      *
145      * @return the first name value for the customer
146      */
147     public String getFirstName()
148     {
149         LOG.debug("returning the First Name: " + myFirstName);
150         return myFirstName;
151     }
152 
153     /**
154      * Sets the first name value for the Customer.
155      * <br>
156      * <br>
157      * The business rules are:
158      * <ul>
159      *   <li>the first name must <strong>not</strong> be null</li>
160      *   <li>the first name must <strong>not</strong> be empty</li>
161      *   <li>the first name must max length of 40 chars</li>
162      *   <li>XSS strings within the first name will be removed</li>
163      * </ul>
164      *
165      * @param firstName the value to set into the customer first name field
166      * @throws IllegalArgumentException if the first name is invalid
167      */
168     public void setFirstName(final String firstName)
169     {
170         LOG.debug("setting the First Name");
171         final int max = 40;
172 
173         if (firstName == null)
174         {
175             LOG.error("First Name must not be null");
176             throw new IllegalArgumentException("First Name must not be null");
177         }
178 
179         String safeFirstName = mySanitizer.sanitizeInput(firstName);
180         if (safeFirstName.isEmpty())
181         {
182             LOG.error("First Name must not be empty");
183             throw new IllegalArgumentException("First Name must not be empty");
184         }
185         if (safeFirstName.length() > max)
186         {
187             LOG.error("First Name must be up to 40 chars in length");
188             throw new IllegalArgumentException("First Name must be up to 40 chars in length");
189         }
190         LOG.debug("setting the First Name to: " + safeFirstName);
191         this.myFirstName = safeFirstName;
192     }
193 
194     /**
195      * Returns the last name value for the Customer.
196      *
197      * @return the last name value for the customer
198      */
199     public String getLastName()
200     {
201         LOG.debug("returning the Last Name: " + myLastName);
202         return myLastName;
203     }
204 
205     /**
206      * Sets the last name value for the Customer.
207      * <p>
208      * The business rules are:
209      * <ul>
210      *   <li>the last name must <strong>not</strong> be null</li>
211      *   <li>the last name must <strong>not</strong> be empty</li>
212      *   <li>the last name must min length of 2 chars</li>
213      *   <li>the last name must max length of 40 chars</li>
214      *   <li>XSS strings within the last name will be removed</li>
215      * </ul>
216      *
217      * @param lastName the value to set into the customer last name field
218      * @throws IllegalArgumentException if the last name is invalid
219      */
220     public void setLastName(final String lastName)
221     {
222         LOG.debug("setting the Last Name");
223         final int max = 40;
224         final int min = 2;
225 
226         if (lastName == null)
227         {
228             LOG.error("Last Name must not be null");
229             throw new IllegalArgumentException("Last Name must not be null");
230         }
231 
232         String safeLastName = mySanitizer.sanitizeInput(lastName);
233         if (safeLastName.isEmpty())
234         {
235             LOG.error("Last Name must not be empty");
236             throw new IllegalArgumentException("Last Name must not be empty");
237         }
238         if (safeLastName.length() > max || safeLastName.length() < min)
239         {
240             LOG.error("Last Name must be between 2 and 40 chars in length");
241             throw new IllegalArgumentException("Last Name must be between 2 and 40 chars in length");
242         }
243         LOG.debug("setting the Last Name to: " + safeLastName);
244         this.myLastName = safeLastName;
245     }
246 
247     /**
248      * Return the Location for the Customer.
249      * <p>
250      * @return the myLocation
251      */
252     public Location getLocation()
253     {
254         LOG.debug("returning the Location: " + myLocation);
255         return myLocation;
256     }
257 
258     /**
259      * Sets the location value for the Customer.
260      * <p>
261      * The business rules are:
262      * <ul>
263      *   <li>the location <strong>may</strong> be null</li>
264      * </ul>
265      *
266      * @param location the value to set into the customer location field
267      * @throws IllegalArgumentException if the location is invalid
268      */
269     public void setLocation(final Location location)
270     {
271         LOG.debug("setting the Location");
272         if (location == null)
273         {
274             LOG.error("Location must not be null");
275             throw new IllegalArgumentException("Location must not be null");
276         }
277         this.myLocation = location;
278     }
279 
280     /**
281      * Returns the phone value for the Customer.
282      *
283      * @return the phone value for the customer
284      */
285     public Phone getPhone()
286     {
287         LOG.debug("returning the Phone: " + myPhone);
288         return myPhone;
289     }
290 
291     /**
292      * Sets the phone value for the Customer.
293      * <p>
294      * The business rules are:
295      * <ul>
296      *   <li>the phone <strong>may</strong> be null</li>
297      * </ul>
298      *
299      * @param phone the value to set into the customer phone field
300      * @throws IllegalArgumentException if the phone is invalid
301      */
302     public void setPhone(final Phone phone)
303     {
304         LOG.debug("setting the Phone");
305         this.myPhone = phone;
306     }
307 
308     /**
309      * The hashCode() method of the Customer class.
310      * <p>
311      * <strong>This method uses:</strong>
312      * <ul>
313      *  <li>id</li>
314      *  <li>first name</li>
315      *  <li>last name</li>
316      *  <li>city</li>
317      *  <li>country</li>
318      * </ul>
319      *
320      * @see java.lang.Object#hashCode()
321      * @return the hashCode value for this Customer object
322      */
323     @Override
324     public int hashCode()
325     {
326         LOG.debug("building HashCode");
327         return new HashCodeBuilder()
328                 .append(getId())
329                 .append(myFirstName)
330                 .append(myLastName)
331                 .append(myLocation.hashCode())
332                 .toHashCode();
333     }
334 
335     /**
336      * The equals() method of the Customer class.
337      * <p>
338      * <strong>This method uses:</strong>
339      * <ul>
340      *  <li>id</li>
341      *  <li>first name</li>
342      *  <li>last name</li>
343      *  <li>city</li>
344      *  <li>country</li>
345      * </ul>
346      *
347      * @see java.lang.Object#equals(Object obj)
348      * @param obj the incoming object to compare against
349      * @return true if the fields being compared are equal
350      */
351     @Override
352     public boolean equals(final Object obj)
353     {
354         LOG.debug("checking equals");
355         if (obj instanceof Customer)
356         {
357             final Customer other = (Customer) obj;
358             return new EqualsBuilder()
359                     .append(getId(), other.getId())
360                     .append(myFirstName, other.myFirstName)
361                     .append(myLastName, other.myLastName)
362                     .append(myLocation.getCity(), other.myLocation.getCity())
363                     .append(myLocation.getCountry(), other.myLocation.getCountry())
364                     .isEquals();
365         }
366         else
367         {
368             return false;
369         }
370     }
371 
372     /**
373      * The toString method for the Customer class.
374      *
375      * this method will return:<br>
376      * Customer [Id=xxx, FirstName=xxx, LastName=xxx, City=xxx,
377      *      Country=xxx, Phone=xxx]
378      */
379     @Override
380     public String toString()
381     {
382         return "Customer [Id=" + getId() + ", FirstName=" + myFirstName
383                 + ", LastName=" + myLastName + ", City="
384                 + myLocation.getCity() + ", Country=" + myLocation.getCountry()
385                 + ", Phone=" + myPhone.getNumber() + "]";
386     }
387 
388 }