View Javadoc
1   /*
2    * Copyright (C) 2020-2023 Dipl.-Inform. Kai Hofmann. All rights reserved!
3    */
4   package de.powerstat.validation.values.strategies;
5   
6   
7   import java.util.Map;
8   import java.util.Objects;
9   import java.util.concurrent.ConcurrentHashMap;
10  
11  import de.powerstat.validation.containers.NTuple4;
12  import de.powerstat.validation.values.EMail;
13  
14  
15  /**
16   * Configurable username validation strategy.
17   */
18  public class UsernameConfigurableStrategy implements IUsernameStrategy
19   {
20    /* *
21     * Logger.
22     */
23    // private static final Logger LOGGER = LogManager.getLogger(UsernameConfigurableStrategy.class);
24  
25    /**
26     * Cache for singletons.
27     */
28    private static final Map<NTuple4<Integer, Integer, String, HandleEMail>, UsernameConfigurableStrategy> CACHE = new ConcurrentHashMap<>();
29  
30    /**
31     * Minimum allowed username length.
32     */
33    private final int minLength;
34  
35    /**
36     * Maximum allowed username length.
37     */
38    private final int maxLength;
39  
40    /**
41     * Regular expression for matching allowed characters.
42     */
43    private final String regexp;
44  
45    /**
46     * EMail handling.
47     *
48     * Could be EMAIL_DENIED, EMAIL_REQUIRED or EMAIL_POSSIBLE
49     */
50    private final HandleEMail emailHandling;
51  
52  
53    /**
54     * Enum for handling of email addresses.
55     */
56    public enum HandleEMail
57     {
58      /**
59       * No email address is denied as username.
60       */
61      EMAIL_DENIED(0),
62  
63      /**
64       * Username must be an email address.
65       */
66      EMAIL_REQUIRED(1),
67  
68      /**
69       * Username can be an email address, but it's not required.
70       */
71      EMAIL_POSSIBLE(2);
72  
73  
74      /**
75       * Action number.
76       */
77      private final int action;
78  
79  
80      /**
81       * Ordinal constructor.
82       *
83       * @param action Action number
84       */
85      HandleEMail(final int action)
86       {
87        this.action = action;
88       }
89  
90  
91      /**
92       * Get action number.
93       *
94       * @return Action number
95       */
96      public int getAction()
97       {
98        return this.action;
99       }
100 
101    }
102 
103 
104   /**
105    * Constructor.
106    *
107    * @param minLength Minimum allowed username length, must be &gt;= 1
108    * @param maxLength Maximum allowed username length, must be &gt;= minLength and &lt;= INTEGER.MAX_VALUE
109    * @param regexp Regular expression for matching characters. Must start with ^ and end with $. Example: ^[@./_0-9a-zA-Z-]+$
110    * @param emailHandling How email addresses as username should be handled: EMAIL_DENIED, EMAIL_REQUIRED or EMAIL_POSSIBLE
111    * @throws IllegalArgumentException If arguments are not as required
112    * @throws NullPointerException If regexp or emailHandling is null
113    */
114   protected UsernameConfigurableStrategy(final int minLength, final int maxLength, final String regexp, final HandleEMail emailHandling)
115    {
116     super();
117     Objects.requireNonNull(regexp, "regexp"); //$NON-NLS-1$
118     Objects.requireNonNull(emailHandling, "emailHandling"); //$NON-NLS-1$
119     if (minLength < 0)
120      {
121       throw new IllegalArgumentException("minLength must be >= 0"); //$NON-NLS-1$
122      }
123     if (maxLength < minLength)
124      {
125       throw new IllegalArgumentException("maxLength >= minLength"); //$NON-NLS-1$
126      }
127     if ((regexp.charAt(0) != '^') || !regexp.endsWith("$")) //$NON-NLS-1$
128      {
129       throw new IllegalArgumentException("regexp does not start with ^ or ends with $"); //$NON-NLS-1$
130      }
131     this.minLength = minLength;
132     this.maxLength = maxLength;
133     this.regexp = regexp;
134     this.emailHandling = emailHandling;
135    }
136 
137 
138   /**
139    * Username validation strategy factory.
140    *
141    * @param minLength Minimum allowed username length, must be &gt;= 1
142    * @param maxLength Maximum allowed username length, must be &gt;= minLength and &lt;= INTEGER.MAX_VALUE
143    * @param regexp Regular expression for matching characters. Must start with ^ and end with $. Example: ^[@./_0-9a-zA-Z-]+$
144    * @param emailHandling How email addresses as username should be handled: EMAIL_DENIED, EMAIL_REQUIRED or EMAIL_POSSIBLE
145    * @return UsernameStrategy object
146    * @throws IllegalArgumentException If arguments
147    * @throws NullPointerException If regexp or emailHandling is null
148    */
149   public static IUsernameStrategy of(final int minLength, final int maxLength, final String regexp, final HandleEMail emailHandling)
150    {
151     final NTuple4<Integer, Integer, String, HandleEMail> tuple = NTuple4.of(minLength, maxLength, regexp, emailHandling);
152     synchronized (UsernameConfigurableStrategy.class)
153      {
154       UsernameConfigurableStrategy obj = UsernameConfigurableStrategy.CACHE.get(tuple);
155       if (obj != null)
156        {
157         return obj;
158        }
159       obj = new UsernameConfigurableStrategy(minLength, maxLength, regexp, emailHandling);
160       UsernameConfigurableStrategy.CACHE.put(tuple, obj);
161       return obj;
162      }
163    }
164 
165 
166   /**
167    * Validation strategy.
168    *
169    * @param username Username
170    * @return true: if username is an email, false otherwise
171    * @throws IllegalArgumentException If the username does not match the configured parameters
172    */
173   @Override
174   public boolean validationStrategy(final String username)
175    {
176     if ((username.length() < this.minLength) || (username.length() > this.maxLength))
177      {
178       throw new IllegalArgumentException("To short or long for an username"); //$NON-NLS-1$
179      }
180     if (!username.matches(this.regexp))
181      {
182       throw new IllegalArgumentException("Username contains illegal character"); //$NON-NLS-1$
183      }
184     // Must or must not be an email address?
185     boolean checkEMail = false;
186     try
187      {
188       /* final EMail email = */ EMail.of(username);
189       checkEMail = true;
190      }
191     catch (final IllegalArgumentException ignore)
192      {
193       // LOGGER.debug("IllegalArgumentException", ignore);
194      }
195     if ((this.emailHandling == HandleEMail.EMAIL_REQUIRED) && !checkEMail)
196      {
197       throw new IllegalArgumentException("Username must be an email address"); //$NON-NLS-1$
198      }
199     if ((this.emailHandling == HandleEMail.EMAIL_DENIED) && checkEMail)
200      {
201       throw new IllegalArgumentException("EMail address is not allowed as username"); //$NON-NLS-1$
202      }
203     return checkEMail;
204    }
205 
206  }