001    // Copyright 2004, 2005 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    //     http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    package org.apache.tapestry.enhance;
016    
017    import java.lang.reflect.Method;
018    import java.lang.reflect.Modifier;
019    import java.util.HashSet;
020    import java.util.Set;
021    
022    import org.apache.hivemind.ErrorLog;
023    import org.apache.hivemind.service.MethodSignature;
024    import org.apache.tapestry.spec.IComponentSpecification;
025    
026    /**
027     * Validates that an enhanced class is correct; checks that all inherited abstract methods are, in
028     * fact, implemented in the class.
029     * 
030     * @author Howard M. Lewis Ship
031     * @since 4.0
032     */
033    public class EnhancedClassValidatorImpl implements EnhancedClassValidator
034    {
035        private ErrorLog _errorLog;
036    
037        public void validate(Class baseClass, Class enhancedClass, IComponentSpecification specification)
038        {
039            Set implementedMethods = new HashSet();
040    
041            Class current = enhancedClass;
042    
043            while (true)
044            {
045                Method[] methods = current.getDeclaredMethods();
046    
047                for (int i = 0; i < methods.length; i++)
048                {
049                    Method m = methods[i];
050    
051                    boolean isAbstract = Modifier.isAbstract(m.getModifiers());
052    
053                    MethodSignature s = new MethodSignature(m);
054    
055                    if (isAbstract)
056                    {
057                        if (implementedMethods.contains(s))
058                            continue;
059    
060                        _errorLog.error(EnhanceMessages.noImplForAbstractMethod(m, current, baseClass
061                                .getName(), enhancedClass), specification.getLocation(), null);
062                    }
063    
064                    implementedMethods.add(s);
065                }
066    
067                // An earlier version of this code walked the interfaces directly,
068                // but it appears that implementing an interface actually
069                // puts abstract method declarations into the class
070                // (at least, in terms of what getDeclaredMethods() returns).
071    
072                // March up to the super class.
073    
074                current = current.getSuperclass();
075    
076                // Once advanced up to a concrete class, we trust that
077                // the compiler did its checking. Alternately, if
078                // we started on java.lang.Object for some reason, current
079                // will be null and we can stop.S
080    
081                if (current == null || !Modifier.isAbstract(current.getModifiers()))
082                    break;
083            }
084    
085        }
086    
087        public void setErrorLog(ErrorLog errorLog)
088        {
089            _errorLog = errorLog;
090        }
091    }