001    /*******************************************************************************
002     * Portions created by Sebastian Thomschke are copyright (c) 2005-2011 Sebastian
003     * Thomschke.
004     * 
005     * All Rights Reserved. This program and the accompanying materials
006     * are made available under the terms of the Eclipse Public License v1.0
007     * which accompanies this distribution, and is available at
008     * http://www.eclipse.org/legal/epl-v10.html
009     * 
010     * Contributors:
011     *     Sebastian Thomschke - initial implementation.
012     *******************************************************************************/
013    package net.sf.oval.constraint;
014    
015    import java.util.regex.Pattern;
016    
017    import net.sf.oval.ConstraintTarget;
018    import net.sf.oval.Validator;
019    import net.sf.oval.configuration.annotation.AbstractAnnotationCheck;
020    import net.sf.oval.context.OValContext;
021    import net.sf.oval.exception.OValException;
022    
023    /**
024     * @author Sebastian Thomschke
025     */
026    public class EmailCheck extends AbstractAnnotationCheck<Email>
027    {
028            private static final long serialVersionUID = 1L;
029    
030            private static final String SPECIAL_CHARACTERS = "'\\(\\)\\-\\.`";
031            private static final String ASCII = "\\w " + SPECIAL_CHARACTERS;
032            private static final String ASCII_WITHOUT_COMMA = "[" + ASCII + "]+";
033            private static final String ASCII_WITH_COMMA = "\"[" + ASCII + ",]+\"";
034            private static final String ASCII_WITH_QUESTION_MARK_AND_EQUALS = "[" + ASCII + "\\?\\=]+";
035            private static final String MIME_ENCODED = "\\=\\?" + ASCII_WITH_QUESTION_MARK_AND_EQUALS + "\\?\\=";
036            private static final String NAME = "(" + ASCII_WITHOUT_COMMA + "|" + ASCII_WITH_COMMA + "|" + MIME_ENCODED + ")";
037    
038            private static final String EMAIL_BASE_PATTERN = "['_A-Za-z0-9-&]+(\\.['_A-Za-z0-9-&]+)*[.]{0,1}@([A-Za-z0-9-])+(\\.[A-Za-z0-9-]+)*((\\.[A-Za-z0-9]{2,})|(\\.[A-Za-z0-9]{2,}\\.[A-Za-z0-9]{2,}))";
039    
040            private static final Pattern EMAIL_PATTERN = Pattern.compile("^" + EMAIL_BASE_PATTERN + "$");
041    
042            private static final Pattern EMAIL_WITH_PERSONAL_NAME_PATTERN = Pattern.compile("^(" + EMAIL_BASE_PATTERN + "|"
043                            + NAME + " +<" + EMAIL_BASE_PATTERN + ">)$");
044    
045            private boolean allowPersonalName;
046    
047            /**
048             * {@inheritDoc}
049             */
050            @Override
051            public void configure(final Email constraintAnnotation)
052            {
053                    super.configure(constraintAnnotation);
054                    setAllowPersonalName(constraintAnnotation.allowPersonalName());
055            }
056    
057            /**
058             * {@inheritDoc}
059             */
060            @Override
061            protected ConstraintTarget[] getAppliesToDefault()
062            {
063                    return new ConstraintTarget[]{ConstraintTarget.VALUES};
064            }
065    
066            /**
067             * @return the allowPersonalName
068             */
069            public boolean isAllowPersonalName()
070            {
071                    return allowPersonalName;
072            }
073    
074            /**
075             * {@inheritDoc}
076             */
077            public boolean isSatisfied(final Object validatedObject, final Object valueToValidate, final OValContext context,
078                            final Validator validator) throws OValException
079            {
080                    if (valueToValidate == null) return true;
081    
082                    if (allowPersonalName) return EMAIL_WITH_PERSONAL_NAME_PATTERN.matcher(valueToValidate.toString()).matches();
083                    return EMAIL_PATTERN.matcher(valueToValidate.toString()).matches();
084            }
085    
086            /**
087             * @param allowPersonalName the allowPersonalName to set
088             */
089            public void setAllowPersonalName(final boolean allowPersonalName)
090            {
091                    this.allowPersonalName = allowPersonalName;
092            }
093    }