001    /*
002     * Copyright 1999-2008 Sun Microsystems, Inc.  All Rights Reserved.
003     * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004     *
005     * This code is free software; you can redistribute it and/or modify it
006     * under the terms of the GNU General Public License version 2 only, as
007     * published by the Free Software Foundation.  Sun designates this
008     * particular file as subject to the "Classpath" exception as provided
009     * by Sun in the LICENSE file that accompanied this code.
010     *
011     * This code is distributed in the hope that it will be useful, but WITHOUT
012     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013     * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014     * version 2 for more details (a copy is included in the LICENSE file that
015     * accompanied this code).
016     *
017     * You should have received a copy of the GNU General Public License version
018     * 2 along with this work; if not, write to the Free Software Foundation,
019     * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020     *
021     * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022     * CA 95054 USA or visit www.sun.com if you need additional information or
023     * have any questions.
024     */
025    
026    package com.sun.tools.doclets.internal.toolkit.util;
027    
028    import com.sun.javadoc.*;
029    import com.sun.tools.doclets.internal.toolkit.Configuration;
030    import java.util.*;
031    
032    /**
033     * For a given class method, build an array of interface methods which it
034     * implements.
035     *
036     * This code is not part of an API.
037     * It is implementation that is subject to change.
038     * Do not use it as an API
039     *
040     * @author Atul M Dambalkar
041     */
042    public class ImplementedMethods {
043    
044        private Map<MethodDoc,Type> interfaces = new HashMap<MethodDoc,Type>();
045        private List<MethodDoc> methlist = new ArrayList<MethodDoc>();
046        private Configuration configuration;
047        private final ClassDoc classdoc;
048        private final MethodDoc method;
049    
050        public ImplementedMethods(MethodDoc method, Configuration configuration) {
051            this.method = method;
052            this.configuration = configuration;
053            classdoc = method.containingClass();
054        }
055    
056        /**
057         * Return the array of interface methods which the method passed in the
058         * constructor is implementing. The search/build order is as follows:
059         * <pre>
060         * 1. Search in all the immediate interfaces which this method's class is
061         *    implementing. Do it recursively for the superinterfaces as well.
062         * 2. Traverse all the superclasses and search recursively in the
063         *    interfaces which those superclasses implement.
064         *</pre>
065         *
066         * @return MethodDoc[] Array of implemented methods.
067         */
068        public MethodDoc[] build(boolean sort) {
069            buildImplementedMethodList(sort);
070            return methlist.toArray(new MethodDoc[methlist.size()]);
071        }
072    
073        public MethodDoc[] build() {
074            return build(true);
075        }
076    
077        public Type getMethodHolder(MethodDoc methodDoc) {
078            return interfaces.get(methodDoc);
079        }
080    
081        /**
082         * Search for the method in the array of interfaces. If found check if it is
083         * overridden by any other subinterface method which this class
084         * implements. If it is not overidden, add it in the method list.
085         * Do this recursively for all the extended interfaces for each interface
086         * from the array passed.
087         */
088        private void buildImplementedMethodList(boolean sort) {
089            List<Type> intfacs = Util.getAllInterfaces(classdoc, configuration, sort);
090            for (Iterator<Type> iter = intfacs.iterator(); iter.hasNext(); ) {
091                Type interfaceType = iter.next();
092                MethodDoc found = Util.findMethod(interfaceType.asClassDoc(), method);
093                if (found != null) {
094                    removeOverriddenMethod(found);
095                    if (!overridingMethodFound(found)) {
096                        methlist.add(found);
097                        interfaces.put(found, interfaceType);
098                    }
099                }
100            }
101        }
102    
103        /**
104         * Search in the method list and check if it contains a method which
105         * is overridden by the method as parameter.  If found, remove the
106         * overridden method from the method list.
107         *
108         * @param method Is this method overriding a method in the method list.
109         */
110        private void removeOverriddenMethod(MethodDoc method) {
111            ClassDoc overriddenClass = method.overriddenClass();
112            if (overriddenClass != null) {
113                for (int i = 0; i < methlist.size(); i++) {
114                    ClassDoc cd = methlist.get(i).containingClass();
115                    if (cd == overriddenClass || overriddenClass.subclassOf(cd)) {
116                        methlist.remove(i);  // remove overridden method
117                        return;
118                    }
119                }
120            }
121        }
122    
123        /**
124         * Search in the already found methods' list and check if it contains
125         * a method which is overriding the method parameter or is the method
126         * parameter itself.
127         *
128         * @param method MethodDoc Method to be searched in the Method List for
129         * an overriding method.
130         */
131        private boolean overridingMethodFound(MethodDoc method) {
132            ClassDoc containingClass = method.containingClass();
133            for (int i = 0; i < methlist.size(); i++) {
134                MethodDoc listmethod = methlist.get(i);
135                if (containingClass == listmethod.containingClass()) {
136                    // it's the same method.
137                    return true;
138                }
139                ClassDoc cd = listmethod.overriddenClass();
140                if (cd == null) {
141                    continue;
142                }
143                if (cd == containingClass || cd.subclassOf(containingClass)) {
144                    return true;
145                }
146            }
147            return false;
148        }
149    }