Package org.apache.tapestry.enhance

Source Code of org.apache.tapestry.enhance.EnhancedClassValidatorImpl

// Copyright 2004, 2005 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package org.apache.tapestry.enhance;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.apache.hivemind.ErrorLog;
import org.apache.hivemind.Location;
import org.apache.hivemind.service.MethodSignature;
import org.apache.tapestry.spec.IComponentSpecification;

/**
* Validates that an enhanced class is correct; checks that all inherited
* abstract methods are, in fact, implemented in the class.
*
* @author Howard M. Lewis Ship
* @since 4.0
*/
public class EnhancedClassValidatorImpl implements EnhancedClassValidator
{

    private ErrorLog _errorLog;

    public void validate(Class baseClass, Class enhancedClass,
            IComponentSpecification specification)
    {
        // Set of MethodSignatures for methods that have a non-abstract
        // implementation
        // The Set is built working from the deepest subclass up to (and
        // including) java.lang.Object

        Set implementedMethods = new HashSet();
        // Key is MethodSignature, value is Method
        // Tracks which methods come from interfaces
        Map interfaceMethods = new HashMap();

        Location location = specification.getLocation();

        Class current = enhancedClass;

        while(true)
        {
            addInterfaceMethods(current, interfaceMethods);

            // Inside Eclipse, for abstract classes, getDeclaredMethods() does
            // NOT report methods
            // inherited from interfaces. For Sun JDK and abstract classes,
            // getDeclaredMethods()
            // DOES report interface methods
            // (as if they were declared by the class itself). This code is
            // needlessly complex so
            // that the checks work in both
            // situations. Basically, I think Eclipse is right and Sun JDK is
            // wrong and we're using
            // the interfaceMethods map as a filter to ignore methods that Sun
            // JDK is attributing
            // to the class.

            Method[] methods = current.getDeclaredMethods();

            for(int i = 0; i < methods.length; i++)
            {
                Method m = methods[i];

                MethodSignature s = new MethodSignature(m);

                boolean isAbstract = Modifier.isAbstract(m.getModifiers());

                if (isAbstract)
                {
                    if (interfaceMethods.containsKey(s)) continue;

                    // If a superclass defines an abstract method that a
                    // subclass implements, then
                    // all's OK.

                    if (implementedMethods.contains(s)) continue;

                    _errorLog.error(EnhanceMessages.noImplForAbstractMethod(m,
                            current, baseClass, enhancedClass), location, null);
                }

                implementedMethods.add(s);
            }

            current = current.getSuperclass();

            // No need to check Object.class; it is concrete and doesn't
            // implement any interfaces,
            // or provide any methods
            // that might be declared in an interface.

            if (current == null || current == Object.class) break;
        }

        Iterator i = interfaceMethods.entrySet().iterator();
        while(i.hasNext())
        {
            Map.Entry entry = (Map.Entry) i.next();

            MethodSignature sig = (MethodSignature) entry.getKey();

            if (implementedMethods.contains(sig)) continue;

            Method method = (Method) entry.getValue();

            _errorLog.error(EnhanceMessages.unimplementedInterfaceMethod(
                    method, baseClass, enhancedClass), location, null);
        }

    }

    private void addInterfaceMethods(Class current, Map interfaceMethods)
    {
        Class[] interfaces = current.getInterfaces();

        for(int i = 0; i < interfaces.length; i++)
            addMethodsFromInterface(interfaces[i], interfaceMethods);
    }

    private void addMethodsFromInterface(Class interfaceClass,
            Map interfaceMethods)
    {
        Method[] methods = interfaceClass.getMethods();

        for(int i = 0; i < methods.length; i++)
        {
            MethodSignature sig = new MethodSignature(methods[i]);

            if (interfaceMethods.containsKey(sig)) continue;

            interfaceMethods.put(sig, methods[i]);
        }
    }

    public void setErrorLog(ErrorLog errorLog)
    {
        _errorLog = errorLog;
    }
}
TOP

Related Classes of org.apache.tapestry.enhance.EnhancedClassValidatorImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.