/*
* @(#)VisibleMemberMap.java 1.4 00/02/02
*
* Copyright 1998-2000 Sun Microsystems, Inc. All Rights Reserved.
*
* This software is the proprietary information of Sun Microsystems, Inc.
* Use is subject to license terms.
*
*/
package com.sun.tools.doclets;
import com.sun.javadoc.*;
import java.lang.*;
import java.util.*;
import java.io.*;
/**
* Algorithm:
*
* @author Atul M Dambalkar
*/
public class VisibleMemberMap {
public static final int INNERCLASSES = 0;
public static final int FIELDS = 1;
public static final int CONSTRUCTORS = 2;
public static final int METHODS = 3;
public static final String STARTLEVEL = "start";
/**
* List of ClassDoc objects for which ClassMembers objects are built.
*/
private final List visibleClasses = new ArrayList();
/**
* Map for each member name on to a map which contains members with same
* name-signature. The mapped map will contain mapping for each MemberDoc
* onto it's respecive level string.
*/
private final Map memberNameMap = new HashMap();
/**
* Map of class and it's ClassMembers object.
*/
private final Map classMap = new HashMap();
/**
* Class whose visible members are requested.
*/
private final ClassDoc classdoc;
/**
* Member kind: InnerClasses/Fields/Methods?
*/
private final int kind;
/**
* Deprected members should be excluded or not?
*/
private final boolean nodepr;
public VisibleMemberMap(ClassDoc classdoc, int kind, boolean nodepr) {
this.classdoc = classdoc;
this.nodepr = nodepr;
this.kind = kind;
new ClassMembers(classdoc, STARTLEVEL).build();
}
public List getVisibleClassesList() {
sort(visibleClasses);
return visibleClasses;
}
public List getMembersFor(ClassDoc cd) {
ClassMembers clmembers = (ClassMembers)(classMap.get(cd));
if (clmembers == null) {
return new ArrayList();
}
return clmembers.getMembers();
}
/**
* Sort the given mixed list of classes and interfaces to a list of
* classes followed by interfaces traversed. Don't sort alphabetically.
*/
private void sort(List list) {
List classes = new ArrayList();
List interfaces = new ArrayList();
for (int i = 0; i < list.size(); i++) {
ClassDoc cd = (ClassDoc)list.get(i);
if (cd.isClass()) {
classes.add(cd);
} else {
interfaces.add(cd);
}
}
list.clear();
list.addAll(classes);
list.addAll(interfaces);
}
private void fillMemberLevelMap(List list, String level) {
for (int i = 0; i < list.size(); i++) {
ProgramElementDoc member = ((ProgramElementDoc)list.get(i));
String membername = getDocName(member);
Map memberLevelMap = (Map)(memberNameMap.get(membername));
if (memberLevelMap == null) {
memberLevelMap = new HashMap();
memberNameMap.put(membername, memberLevelMap);
}
memberLevelMap.put(member, level);
}
}
/**
* Return the name for each doc item. For example,
* if the doc item is of type PackageDoc for "java.lang" return string
* "java.lang", if the doc item is ClassDoc for "java.lang.Object" return
* string "java.lang.Object", if the doc item is MethodDoc for method
* "wait()" in java.lang.Object class, then return string wait()".
*
* @param doc Doc Item for which name to be returned.
* @return String name string as described above.
*/
protected static String getDocName(ProgramElementDoc doc) {
if (doc.isMethod() || doc.isConstructor()) {
return doc.name() + ((ExecutableMemberDoc)doc).signature();
} else if (doc.isField()) {
return doc.name();
} else { // it's a class or interface
return "clint" + doc.name();
}
}
private class ClassMembers {
/**
* The mapping class, whose inherited members are put in the
* {@link #members} list.
*/
private ClassDoc mappingClass;
/**
* List of inherited members from the mapping class.
*/
private List members = new ArrayList();
/**
* Level/Depth of inheritance.
*/
private String level;
/**
* Return list of inherited members from mapping class.
*
* @return List Inherited members.
*/
public List getMembers() {
return members;
}
private ClassMembers(ClassDoc mappingClass, String level) {
this.mappingClass = mappingClass;
this.level = level;
if (!classMap.containsKey(mappingClass) &&
checkAccess(mappingClass)) {
classMap.put(mappingClass, this);
visibleClasses.add(mappingClass);
}
/*if (kind == CONSTRUCTORS) {
addMembers(mappingClass);
} else {
mapClass(this);
} */
}
private void build() {
if (kind == CONSTRUCTORS) {
addMembers(mappingClass);
} else {
mapClass(this);
}
}
private void mapClass(ClassMembers clmembers) {
if (checkAccess(mappingClass)) {
clmembers = this;
}
clmembers.addMembers(mappingClass);
ClassDoc[] interfaces = mappingClass.interfaces();
for (int i = 0; i < interfaces.length; i++) {
String locallevel = level + (i + 1);
ClassMembers cm = new ClassMembers(interfaces[i], locallevel);
cm.mapClass(clmembers);
}
if (mappingClass.isClass()) {
ClassDoc superclass = mappingClass.superclass();
if (superclass != null) {
ClassMembers cm = new ClassMembers(superclass,
level + "c");
cm.mapClass(clmembers);
}
}
}
private boolean checkAccess(ClassDoc cd) {
return cd.isPublic() ||
cd.isProtected() ||
(cd.isIncluded() && cd.isPackagePrivate());
}
/**
* Get all the valid members from the mapping class. Get the list of
* members for the class to be included into(ctii), also get the level
* string for ctii. If mapping class member is not already in the
* inherited member list and if it is visible in the ctii and not
* overridden, put such a member in the inherited member list.
* Adjust member-level-map, class-map.
*/
private void addMembers(ClassDoc fromClass) {
List cdmembers = getClassMembers(fromClass);
List incllist = new ArrayList();
for (int i = 0; i < cdmembers.size(); i++) {
ProgramElementDoc pgmelem =
(ProgramElementDoc)(cdmembers.get(i));
if (!found(members, pgmelem) &&
isVisible(pgmelem) &&
!isOverridden(pgmelem, level)) {
incllist.add(pgmelem);
}
}
members.addAll(incllist);
fillMemberLevelMap(members, level);
}
/**
* Is given doc item visible in given classdoc in terms fo inheritance?
* The given doc item is visible in the given classdoc if it is public
* or protected and if it is package-private if it's containing class
* is in the same package as the given classdoc.
*/
private boolean isVisible(ProgramElementDoc pgmdoc) {
if (pgmdoc.containingClass() == mappingClass) {
return true;
} else if (pgmdoc.isPrivate()) {
return false;
} else if (pgmdoc.isPackagePrivate()) {
return pgmdoc.containingClass().containingPackage() ==
mappingClass.containingPackage();
}
return true;
}
/**
* Return all available class members.
*/
private List getClassMembers(ClassDoc cd) {
ProgramElementDoc[] members = null;
switch (kind) {
case INNERCLASSES:
members = cd.innerClasses();
break;
case FIELDS:
members = cd.fields();
break;
case CONSTRUCTORS:
members = cd.constructors();
break;
case METHODS:
members = cd.methods();
break;
default:
members = new ProgramElementDoc[0];
}
if (nodepr) {
return Util.excludeDeprecatedMembersAsList(members);
}
return Util.asList(members);
}
private boolean found(List list, ProgramElementDoc elem) {
for (int i = 0; i < list.size(); i++) {
ProgramElementDoc pgmelem = (ProgramElementDoc)list.get(i);
if (Util.matches(pgmelem, elem)) {
return true;
}
}
return false;
}
/**
* Is member overridden? The member is overridden if it is found in the
* same level hierarchy e.g. member at level "11" overrides member at
* level "111".
*/
private boolean isOverridden(ProgramElementDoc pgmdoc, String level) {
Map memberLevelMap = (Map)(memberNameMap.get(getDocName(pgmdoc)));
if (memberLevelMap == null) {
return false;
}
String mappedlevel = null;
Iterator iterator = memberLevelMap.values().iterator();
while (iterator.hasNext()) {
mappedlevel = (String)(iterator.next());
if (mappedlevel.equals(STARTLEVEL) ||
level.startsWith(mappedlevel)) {
return true;
}
}
return false;
}
}
}
|