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.configuration.annotation;
014    
015    import java.lang.annotation.Annotation;
016    import java.lang.reflect.Method;
017    
018    import net.sf.oval.AbstractCheck;
019    import net.sf.oval.ConstraintTarget;
020    import net.sf.oval.internal.Log;
021    import net.sf.oval.internal.util.ReflectionUtils;
022    
023    /**
024     * Partial implementation of check classes configurable via annotations.
025     * 
026     * @author Sebastian Thomschke
027     */
028    public abstract class AbstractAnnotationCheck<ConstraintAnnotation extends Annotation> extends AbstractCheck
029                    implements
030                            AnnotationCheck<ConstraintAnnotation>
031    {
032            private static final long serialVersionUID = 1L;
033    
034            private static final Log LOG = Log.getLog(AbstractAnnotationCheck.class);
035    
036            /**
037             * {@inheritDoc}
038             */
039            public void configure(final ConstraintAnnotation constraintAnnotation)
040            {
041                    final Class< ? > constraintClazz = constraintAnnotation.getClass();
042    
043                    /*
044                     * Retrieve the message value from the constraint annotation via reflection.
045                     * Using reflection is required because annotations do not support inheritance and 
046                     * therefore cannot implement an interface that could be used for a down cast here.
047                     */
048                    final Method getMessage = ReflectionUtils.getMethod(constraintClazz, "message", (Class< ? >[]) null);
049                    if (getMessage == null)
050                            LOG.debug(
051                                            "Cannot determine constraint error message based on annotation {1} since attribtue message() is not defined.",
052                                            constraintClazz.getName());
053                    else
054                            try
055                            {
056                                    setMessage((String) getMessage.invoke(constraintAnnotation, (Object[]) null));
057                            }
058                            catch (final Exception ex)
059                            {
060                                    LOG.warn("Cannot determine constraint error message based on annotation {1}",
061                                                    constraintClazz.getName(), ex);
062    
063                                    try
064                                    {
065                                            setMessage(constraintClazz.getName() + ".violated");
066                                    }
067                                    catch (final UnsupportedOperationException uex)
068                                    {
069                                            // ignore
070                                    }
071                            }
072    
073                    /*
074                     * Retrieve the appliesTo value from the constraint annotation via reflection.
075                     */
076                    final Method getAppliesTo = ReflectionUtils.getMethod(constraintClazz, "appliesTo", (Class< ? >[]) null);
077                    if (getAppliesTo == null)
078                            LOG.debug(
079                                            "Cannot determine constraint targets based on annotation {1} since attribtue appliesTo() is not defined.",
080                                            constraintClazz.getName());
081                    else
082                            try
083                            {
084                                    setAppliesTo((ConstraintTarget[]) getAppliesTo.invoke(constraintAnnotation, (Object[]) null));
085                            }
086                            catch (final Exception ex)
087                            {
088                                    LOG.warn("Cannot determine constraint targets based on annotation {1}", constraintClazz.getName(), ex);
089                            }
090    
091                    /*
092                     * Retrieve the error code value from the constraint annotation via reflection.
093                     */
094                    final Method getErrorCode = ReflectionUtils.getMethod(constraintClazz, "errorCode", (Class< ? >[]) null);
095                    if (getErrorCode == null)
096                            LOG.debug(
097                                            "Cannot determine constraint error code based on annotation {1} since attribtue errorCode() is not defined.",
098                                            constraintClazz.getName());
099                    else
100                            try
101                            {
102                                    setErrorCode((String) getErrorCode.invoke(constraintAnnotation, (Object[]) null));
103                            }
104                            catch (final Exception ex)
105                            {
106                                    LOG.warn("Cannot determine constraint error code based on annotation {1}", constraintClazz.getName(),
107                                                    ex);
108                                    try
109                                    {
110                                            setErrorCode(constraintClazz.getName());
111                                    }
112                                    catch (final UnsupportedOperationException uex)
113                                    {
114                                            // ignore
115                                    }
116                            }
117    
118                    /*
119                     * Retrieve the severity value from the constraint annotation via reflection.
120                     */
121                    final Method getSeverity = ReflectionUtils.getMethod(constraintClazz, "severity", (Class< ? >[]) null);
122                    if (getSeverity == null)
123                            LOG.debug(
124                                            "Cannot determine constraint severity based on annotation {1} since attribtue severity() is not defined.",
125                                            constraintClazz.getName());
126                    else
127                            try
128                            {
129                                    setSeverity(((Number) getSeverity.invoke(constraintAnnotation, (Object[]) null)).intValue());
130                            }
131                            catch (final Exception ex)
132                            {
133                                    LOG.warn("Cannot determine constraint severity based on annotation {1}", constraintClazz.getName(), ex);
134                            }
135    
136                    /*
137                     * Retrieve the profiles value from the constraint annotation via reflection.
138                     */
139                    final Method getProfiles = ReflectionUtils.getMethod(constraintClazz, "profiles", (Class< ? >[]) null);
140                    if (getProfiles == null)
141                            LOG.debug(
142                                            "Cannot determine constraint profiles based on annotation {1} since attribtue profiles() is not defined.",
143                                            constraintClazz.getName());
144                    else
145                            try
146                            {
147                                    setProfiles((String[]) getProfiles.invoke(constraintAnnotation, (Object[]) null));
148                            }
149                            catch (final Exception ex)
150                            {
151                                    LOG.warn("Cannot determine constraint profiles based on annotation {1}", constraintClazz.getName(), ex);
152                            }
153    
154                    /*
155                     * Retrieve the profiles value from the constraint annotation via reflection.
156                     */
157                    final Method getTarget = ReflectionUtils.getMethod(constraintClazz, "target", (Class< ? >[]) null);
158                    if (getTarget == null)
159                            LOG.debug(
160                                            "Cannot determine constraint target based on annotation {1} since attribtue target() is not defined.",
161                                            constraintClazz.getName());
162                    else
163                            try
164                            {
165                                    setTarget((String) getTarget.invoke(constraintAnnotation, (Object[]) null));
166                            }
167                            catch (final Exception ex)
168                            {
169                                    LOG.warn("Cannot determine constraint target based on annotation {1}", constraintClazz.getName(), ex);
170                            }
171    
172                    /*
173                     * Retrieve the when formula from the constraint annotation via reflection.
174                     */
175                    final Method getWhen = ReflectionUtils.getMethod(constraintClazz, "when", (Class< ? >[]) null);
176                    if (getWhen == null)
177                            LOG.debug(
178                                            "Cannot determine constraint when formula based on annotation {1} since attribtue when() is not defined.",
179                                            constraintClazz.getName());
180                    else
181                            try
182                            {
183                                    setWhen((String) getWhen.invoke(constraintAnnotation, (Object[]) null));
184                            }
185                            catch (final Exception ex)
186                            {
187                                    LOG.warn("Cannot determine constraint when formula based on annotation {1}", constraintClazz.getName(),
188                                                    ex);
189                            }
190            }
191    }