Wednesday, December 21, 2011

Email validatation with regular expression.

Email Regular Expression Pattern
 
^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*@
[A-Za-z0-9]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$

Description
^   #start of the line
  [_A-Za-z0-9-]+ #  must start with string in the bracket [ ], must contains one or more (+)
  (   #  start of group #1
    \\.[_A-Za-z0-9-]+ #     follow by a dot "." and string in the bracket [ ], must contains one or more (+)
  )*   #  end of group #1, this group is optional (*)
    @   #     must contains a "@" symbol
     [A-Za-z0-9]+       #        follow by string in the bracket [ ], must contains one or more (+)
      (   #    start of group #2 - first level TLD checking
       \\.[A-Za-z0-9]+  #      follow by a dot "." and string in the bracket [ ], must contains one or more (+)
      )*  #    end of group #2, this group is optional (*)
      (   #    start of group #3 - second level TLD checking
       \\.[A-Za-z]{2,}  #      follow by a dot "." and string in the bracket [ ], with minimum length of 2
      )   #    end of group #3
$   #end of the line


Whole combination is means, email address must start with “_A-Za-z0-9-” , optional follow by “.[_A-Za-z0-9-]“, and end with a “@” symbol. The email’s domain name must start with “A-Za-z0-9″, follow by first level Tld (.com, .net) “.[A-Za-z0-9]” and optional follow by a second level Tld (.com.au, .com.my) “\\.[A-Za-z]{2,}”, where second level Tld must start with a dot “.” and length must equal or more than 2 characters.

Java Regular Expression Example

Here’s a Java example to show the use of regex to validate an email address.

/*
 * restTestApp - EmailValidator.java, Dec 21, 2011 11:44:50 PM
 *

 */
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * The Class EmailValidator.
 * @author Rajakrishna V. Reddy
 */
public class EmailValidator
{
   
    /** The pattern. */
    private Pattern pattern;
   
    /** The matcher. */
    private Matcher matcher;
   
    /** The Constant EMAIL_PATTERN. */
    private static final String EMAIL_PATTERN = "^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";
   
    /**
     * Instantiates a new email validator.
     */
    public EmailValidator()
    {
        pattern = Pattern.compile(EMAIL_PATTERN);
    }
   
    /**
     * Validate hex with regular expression.
     *
     * @param hex
     *            hex for validation
     * @return true valid hex, false invalid hex
     */
    public boolean validate(final String hex)
    {
        matcher = pattern.matcher(hex);
        return matcher.matches();
    }
   
    public static void main(String[] args)
    {
        final String email = "yahoo.com@yahoo.com";
        final EmailValidator emailValidator = new EmailValidator();
        System.out.println("Is a Valid Email: "+emailValidator.validate(email));
    }
}

Emails that match:

1. “mkyong@yahoo.com”, “mkyong-100@yahoo.com”,”mkyong.100@yahoo.com”
2. “mkyong111@mkyong.com”, “mkyong-100@mkyong.net”,”mkyong.100@mkyong.com.au”
3. “mkyong@1.com”, “mkyong@gmail.com.com”

Emails that doesn’t match:

1. “mkyong” – must contains “@” symbol
2. “mkyong@.com.my” – tld can not start with dot “.”
3. “mkyong123@gmail.a” – “.a” is not a valid tld, last tld must contains at least two characters
4. “mkyong123@.com” – tld can not start with dot “.”
5. “mkyong123@.com.com” – tld can not start with dot “.”
6. “.mkyong@mkyong.com” – email’s first character can not start with dot “.”
7. “mkyong()*@gmail.com” – email’s is only allow character, digit, underscore and dash
8. “mkyong@%*.com” – email’s tld is only allow character and digit
9. “mkyong..2002@gmail.com” – double dots “.” are not allow
10. “mkyong.@gmail.com” – email’s last character can not end with dot “.”
11. “mkyong@mkyong@gmail.com” – double “@” is not allow
12. “mkyong@gmail.com.1a” -email’s tld which has two characters can not contains digit

Unit Test – Result

Here’s the unit test result.
Email is valid : mkyong@yahoo.com , true
Email is valid : mkyong-100@yahoo.com , true
Email is valid : mkyong.100@yahoo.com , true
Email is valid : mkyong111@mkyong.com , true
Email is valid : mkyong-100@mkyong.net , true
Email is valid : mkyong.100@mkyong.com.au , true
Email is valid : mkyong@1.com , true
Email is valid : mkyong@gmail.com.com , true
Email is valid : mkyong , false
Email is valid : mkyong@.com.my , false
Email is valid : mkyong123@gmail.a , false
Email is valid : mkyong123@.com , false
Email is valid : mkyong123@.com.com , false
Email is valid : .mkyong@mkyong.com , false
Email is valid : mkyong()*@gmail.com , false
Email is valid : mkyong@%*.com , false
Email is valid : mkyong..2002@gmail.com , false
Email is valid : mkyong.@gmail.com , false
Email is valid : mkyong@mkyong@gmail.com , false
Email is valid : mkyong@gmail.com.1a , false
PASSED: ValidEmailTest([Ljava.lang.String;@1a626f)
PASSED: InValidEmailTest([Ljava.lang.String;@1975b59)
 
===============================================
    com.mkyong.regex.EmailValidatorTest
    Tests run: 2, Failures: 0, Skips: 0
===============================================
 
===============================================
mkyong
Total tests run: 2, Failures: 0, Skips: 0
===============================================
 

Reference

  1. http://en.wikipedia.org/wiki/E-mail_address
  2. http://tools.ietf.org/html/rfc2822#section-3.4.1
 

Tuesday, December 20, 2011

Log4J Powers Unveiled-IV - Direct log output to different appenders by level.

Yes it is. Setting the Threshold option of any appender extending AppenderSkeleton, (most log4j appenders extend AppenderSkeleton) to filter out all log events with lower level than the value of the threshold option.
For example, setting the threshold of an appender to DEBUG also allow INFO, WARN, ERROR and FATAL messages to log along with DEBUG messages. This is usually acceptable as there is little use for DEBUG messages without the surrounding INFO, WARN, ERROR and FATAL messages. Similarly, setting the threshold of an appender to ERROR will filter out DEBUG, INFO and WARN messages but not ERROR or FATAL messages.
This policy usually best encapsulates what the user actually wants to do, as opposed to her mind-projected solution.
See examples/sort4.lcf for an example threshold configuration.
If you must filter events by exact level match, then you can attach a LevelMatchFilter to any appender to filter out logging events by exact level match.

Log4J Powers Unveiled-III - Defining my own Level.



"It is possible, but rarely appropriate. The request is commonly for a level named something like "audit" that doesn't obviously fit in the progression "trace", "debug", "info", "warn", "error" and "fatal". In that case, the request for a level is really a request for a mechanism to specify a different audience. The appropriate mechanism is to use a distinct logger name (or tree) for "audit" related messages." -- From Log4J.


If you need to add your own logging level in log4j, then you can do it as follows. You will have to create your own class which will extend from Level. Here's a sample code for the same: 

MyTraceLevel.java: 
view plaincopy to clipboardprint?
  1. package org.myapp.log;  
  2.   
  3. import org.apache.log4j.Level;  
  4. /** 
  5.  * My own {@link org.apache.log4j.Level} for logging.  
  6.  *  
  7.  * @author Jaikiran Pai  
  8.  *  
  9.  */   
  10. public class MyTraceLevel extends Level {   
  11.   
  12.  /**  
  13.   * Value of my trace level. This value is lesser than  
  14.   * {@link org.apache.log4j.Priority#DEBUG_INT}  
  15.   * and higher than {@link org.apache.log4j.Level#TRACE_INT}  
  16.   */   
  17.  public static final int MY_TRACE_INT = DEBUG_INT - 10;   
  18.    
  19.  /**  
  20.   * {@link Level} representing my log level  
  21.   */   
  22.  public static final Level MY_TRACE = new MyTraceLevel(MY_TRACE_INT,"MY_TRACE",7);  
  23.   
  24.      /** 
  25.        * Constructor 
  26.         * 
  27.        * @param arg0 
  28.        * @param arg1 
  29.        * @param arg2 
  30.         */  
  31.      protected MyTraceLevel(int arg0, String arg1, int arg2) {  
  32.          super(arg0, arg1, arg2);  
  33.   
  34.      }  
  35.   
  36.      /** 
  37.       * Checks whether sArg is "MY_TRACE" level. If yes then returns  
  38.       * {@link MyTraceLevel#MY_TRACE}, else calls  
  39.       * {@link MyTraceLevel#toLevel(String, Level)} passing it  
  40.       * {@link Level#DEBUG} as the defaultLevel. 
  41.        * 
  42.        * @see Level#toLevel(java.lang.String) 
  43.        * @see Level#toLevel(java.lang.String, org.apache.log4j.Level) 
  44.        * 
  45.        */  
  46.      public static Level toLevel(String sArg) {  
  47.          if (sArg != null && sArg.toUpperCase().equals("MY_TRACE")) {  
  48.              return MY_TRACE;  
  49.          }  
  50.          return (Level) toLevel(sArg, Level.DEBUG);  
  51.      }  
  52.   
  53.      /** 
  54.       * Checks whether val is {@link MyTraceLevel#MY_TRACE_INT}.  
  55.   * If yes then returns {@link MyTraceLevel#MY_TRACE}, else calls  
  56.   * {@link MyTraceLevel#toLevel(int, Level)} passing it {@link Level#DEBUG} 
  57.   * as the defaultLevel 
  58.   * 
  59.        * @see Level#toLevel(int) 
  60.        * @see Level#toLevel(int, org.apache.log4j.Level) 
  61.        * 
  62.        */  
  63.      public static Level toLevel(int val) {  
  64.          if (val == MY_TRACE_INT) {  
  65.              return MY_TRACE;  
  66.          }  
  67.          return (Level) toLevel(val, Level.DEBUG);  
  68.      }  
  69.   
  70.      /** 
  71.       * Checks whether val is {@link MyTraceLevel#MY_TRACE_INT}.  
  72.       * If yes then returns {@link MyTraceLevel#MY_TRACE}, 
  73.       * else calls {@link Level#toLevel(int, org.apache.log4j.Level)} 
  74.       * 
  75.       * @see Level#toLevel(int, org.apache.log4j.Level) 
  76.       */  
  77.      public static Level toLevel(int val, Level defaultLevel) {  
  78.          if (val == MY_TRACE_INT) {  
  79.              return MY_TRACE;  
  80.          }  
  81.          return Level.toLevel(val,defaultLevel);  
  82.      }  
  83.   
  84.      /** 
  85.       * Checks whether sArg is "MY_TRACE" level.  
  86.   * If yes then returns {@link MyTraceLevel#MY_TRACE}, else calls 
  87.   * {@link Level#toLevel(java.lang.String, org.apache.log4j.Level)} 
  88.   * 
  89.   * @see Level#toLevel(java.lang.String, org.apache.log4j.Level) 
  90.   */  
  91.  public static Level toLevel(String sArg, Level defaultLevel) {       
  92.         if(sArg != null && sArg.toUpperCase().equals("MY_TRACE")) {  
  93.             return MY_TRACE;  
  94.         }  
  95.         return Level.toLevel(sArg,defaultLevel);  
  96.  }  
  97. }  

Now, you will have to configure your log4j.xml: 
view plaincopy to clipboardprint?
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">   
  3. <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"debug="false">   
  4. <!-- ================================= -->   
  5. <!-- Preserve messages in a local file -->   
  6. <!-- ================================= -->   
  7. <!-- A size based rolling appender -->   
  8. <appender name="FILE" class="org.apache.log4j.FileAppender">   
  9. <param name="File" value="D:/log/myLogFile.log"/>   
  10. <param name="Append" value="false"/>   
  11. <layout class="org.apache.log4j.PatternLayout">   
  12. <param name="ConversionPattern" value="%d{ISO8601} %-5p [%c] %m%n"/>   
  13. </layout>   
  14. </appender>   
  15. <!-- ============================== -->   
  16. <!-- Append messages to the console -->   
  17. <!-- ============================== -->   
  18. <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">   
  19. <param name="Target" value="System.out"/>   
  20. <param name="Threshold" value="INFO"/>   
  21. <layout class="org.apache.log4j.PatternLayout">   
  22. <!-- The default pattern: Date Priority [Category] Message\n -->   
  23. <param name="ConversionPattern" value="%d{ISO8601} %-5p [%c{1}] %m%n"/>   
  24. </layout>   
  25. </appender>   
  26. <!-- ================ -->   
  27. <!-- Limit categories -->   
  28. <!-- ================ -->   
  29. <category name="org.myapp">   
  30. <priority value="MY_TRACE" class="org.myapp.log.MyTraceLevel" />   
  31. <appender-ref ref="FILE"/>   
  32. </category>   
  33. <!-- ======================= -->   
  34. <!-- Setup the Root category -->   
  35. <!-- ======================= -->   
  36. <root>   
  37. <appender-ref ref="CONSOLE"/>   
  38. </root>   
  39. </log4j:configuration>   


Here's a test program which can be used for testing whether the new log level that you introduced is being identified or not: 

TestMyLogLevel.java:
  1. package org.myapp.core;   
  2.   
  3. import org.apache.log4j.Level;   
  4. import org.apache.log4j.Logger;   
  5. import org.myapp.log.MyTraceLevel;   
  6.   
  7. /**  
  8.  * Tests whether the new log level {@link org.myapp.log.MyTraceLevel#MY_TRACE}  
  9.  * is working  
  10.  *  
  11.  * @author Jaikiran Pai  
  12.  *  
  13.  */   
  14. public class TestMyLogLevel {   
  15.   
  16.  /**  
  17.   * Writes a log message with {@link org.myapp.log.MyTraceLevel#MY_TRACE}  
  18.   * and another message with {@link Level#DEBUG} 
  19.        * 
  20.        * @param args 
  21.        */  
  22.  public static void main(String[] args) {  
  23.   Logger logger = Logger.getLogger(TestMyLogLevel.class);  
  24.   logger.log(MyTraceLevel.MY_TRACE,"I am MY_TRACE log");  
  25.   logger.log(Level.DEBUG ,"I am a debug message");  
  26.  }  
  27. }  

Finally, here's the log file that got generated: 
  1. 2006-07-12 13:45:40,633 MY_TRACE [org.myapp.core.TestMyLogLevel] I am MY_TRACE log   
  2. 2006-07-12 13:45:40,633 DEBUG [org.myapp.core.TestMyLogLevel] I am a debug message   

Points to note: 

- The int value that you specify for your log level is important. Here i have defined "MY_TRACE" log level is to be higher than the DEBUG level but lower than the TRACE level provided by log4j. So whenever you have set a priority level to DEBUG on the category(in your log4j.xml file), the MY_TRACE level logs will *NOT* make it to the log file.