duke@1: /* ohair@554: * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved. duke@1: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@1: * duke@1: * This code is free software; you can redistribute it and/or modify it duke@1: * under the terms of the GNU General Public License version 2 only, as ohair@554: * published by the Free Software Foundation. Oracle designates this duke@1: * particular file as subject to the "Classpath" exception as provided ohair@554: * by Oracle in the LICENSE file that accompanied this code. duke@1: * duke@1: * This code is distributed in the hope that it will be useful, but WITHOUT duke@1: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@1: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@1: * version 2 for more details (a copy is included in the LICENSE file that duke@1: * accompanied this code). duke@1: * duke@1: * You should have received a copy of the GNU General Public License version duke@1: * 2 along with this work; if not, write to the Free Software Foundation, duke@1: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@1: * ohair@554: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ohair@554: * or visit www.oracle.com if you need additional information or have any ohair@554: * questions. duke@1: */ duke@1: duke@1: package com.sun.tools.doclets.internal.toolkit.util.links; duke@1: duke@1: import com.sun.javadoc.*; duke@1: duke@1: /** duke@1: * A factory that constructs links from given link information. duke@1: * duke@1: * @author Jamie Ho duke@1: * @since 1.5 duke@1: */ duke@1: public abstract class LinkFactory { duke@1: duke@1: /** duke@1: * Return an empty instance of the link output object. duke@1: * duke@1: * @return an empty instance of the link output object. duke@1: */ duke@1: protected abstract LinkOutput getOutputInstance(); duke@1: duke@1: /** duke@1: * Constructs a link from the given link information. duke@1: * duke@1: * @param linkInfo the information about the link. duke@1: * @return the output of the link. duke@1: */ duke@1: public LinkOutput getLinkOutput(LinkInfo linkInfo) { duke@1: if (linkInfo.type != null) { duke@1: Type type = linkInfo.type; duke@1: LinkOutput linkOutput = getOutputInstance(); duke@1: if (type.isPrimitive()) { duke@1: //Just a primitive. duke@1: linkInfo.displayLength += type.typeName().length(); duke@1: linkOutput.append(type.typeName()); duke@1: } else if (type.asWildcardType() != null) { duke@1: //Wildcard type. duke@1: linkInfo.isTypeBound = true; duke@1: linkInfo.displayLength += 1; duke@1: linkOutput.append("?"); duke@1: WildcardType wildcardType = type.asWildcardType(); duke@1: Type[] extendsBounds = wildcardType.extendsBounds(); duke@1: for (int i = 0; i < extendsBounds.length; i++) { duke@1: linkInfo.displayLength += i > 0 ? 2 : 9; duke@1: linkOutput.append(i > 0 ? ", " : " extends "); duke@1: setBoundsLinkInfo(linkInfo, extendsBounds[i]); duke@1: linkOutput.append(getLinkOutput(linkInfo)); duke@1: } duke@1: Type[] superBounds = wildcardType.superBounds(); duke@1: for (int i = 0; i < superBounds.length; i++) { duke@1: linkInfo.displayLength += i > 0 ? 2 : 7; duke@1: linkOutput.append(i > 0 ? ", " : " super "); duke@1: setBoundsLinkInfo(linkInfo, superBounds[i]); duke@1: linkOutput.append(getLinkOutput(linkInfo)); duke@1: } duke@1: } else if (type.asTypeVariable()!= null) { duke@1: linkInfo.isTypeBound = true; duke@1: //A type variable. duke@1: Doc owner = type.asTypeVariable().owner(); duke@1: if ((! linkInfo.excludeTypeParameterLinks) && duke@1: owner instanceof ClassDoc) { duke@1: linkInfo.classDoc = (ClassDoc) owner; duke@1: linkInfo.label = type.typeName(); jjg@74: linkOutput.append(getClassLink(linkInfo)); duke@1: } else { duke@1: //No need to link method type parameters. duke@1: linkInfo.displayLength += type.typeName().length(); duke@1: linkOutput.append(type.typeName()); duke@1: } duke@1: duke@1: Type[] bounds = type.asTypeVariable().bounds(); duke@1: if (! linkInfo.excludeTypeBounds) { duke@1: linkInfo.excludeTypeBounds = true; duke@1: for (int i = 0; i < bounds.length; i++) { duke@1: linkInfo.displayLength += i > 0 ? 2 : 9; duke@1: linkOutput.append(i > 0 ? " & " : " extends "); duke@1: setBoundsLinkInfo(linkInfo, bounds[i]); duke@1: linkOutput.append(getLinkOutput(linkInfo)); duke@1: } duke@1: } duke@1: } else if (type.asClassDoc() != null) { duke@1: //A class type. duke@1: if (linkInfo.isTypeBound && duke@1: linkInfo.excludeTypeBoundsLinks) { duke@1: //Since we are excluding type parameter links, we should not duke@1: //be linking to the type bound. duke@1: linkInfo.displayLength += type.typeName().length(); duke@1: linkOutput.append(type.typeName()); duke@1: linkOutput.append(getTypeParameterLinks(linkInfo)); duke@1: return linkOutput; duke@1: } else { duke@1: linkInfo.classDoc = type.asClassDoc(); jjg@74: linkOutput = getClassLink(linkInfo); duke@1: if (linkInfo.includeTypeAsSepLink) { duke@1: linkOutput.append(getTypeParameterLinks(linkInfo, false)); duke@1: } duke@1: } duke@1: } duke@1: duke@1: if (linkInfo.isVarArg) { duke@1: if (type.dimension().length() > 2) { duke@1: //Javadoc returns var args as array. duke@1: //Strip out the first [] from the var arg. duke@1: linkInfo.displayLength += type.dimension().length()-2; duke@1: linkOutput.append(type.dimension().substring(2)); duke@1: } duke@1: linkInfo.displayLength += 3; duke@1: linkOutput.append("..."); duke@1: } else { duke@1: linkInfo.displayLength += type.dimension().length(); duke@1: linkOutput.append(type.dimension()); duke@1: } duke@1: return linkOutput; duke@1: } else if (linkInfo.classDoc != null) { duke@1: //Just a class link jjg@74: LinkOutput linkOutput = getClassLink(linkInfo); duke@1: if (linkInfo.includeTypeAsSepLink) { duke@1: linkOutput.append(getTypeParameterLinks(linkInfo, false)); duke@1: } duke@1: return linkOutput; duke@1: } else { duke@1: return null; duke@1: } duke@1: } duke@1: duke@1: private void setBoundsLinkInfo(LinkInfo linkInfo, Type bound) { duke@1: linkInfo.classDoc = null; duke@1: linkInfo.label = null; duke@1: linkInfo.type = bound; duke@1: } duke@1: duke@1: /** duke@1: * Return the link to the given class. duke@1: * duke@1: * @param linkInfo the information about the link to construct. duke@1: * duke@1: * @return the link for the given class. duke@1: */ duke@1: protected abstract LinkOutput getClassLink(LinkInfo linkInfo); duke@1: duke@1: /** duke@1: * Return the link to the given type parameter. duke@1: * duke@1: * @param linkInfo the information about the link to construct. duke@1: * @param typeParam the type parameter to link to. duke@1: */ duke@1: protected abstract LinkOutput getTypeParameterLink(LinkInfo linkInfo, duke@1: Type typeParam); duke@1: duke@1: /** duke@1: * Return the links to the type parameters. duke@1: * duke@1: * @param linkInfo the information about the link to construct. duke@1: * @return the links to the type parameters. duke@1: */ duke@1: public LinkOutput getTypeParameterLinks(LinkInfo linkInfo) { duke@1: return getTypeParameterLinks(linkInfo, true); duke@1: } duke@1: duke@1: /** duke@1: * Return the links to the type parameters. duke@1: * duke@1: * @param linkInfo the information about the link to construct. duke@1: * @param isClassLabel true if this is a class label. False if it is duke@1: * the type parameters portion of the link. duke@1: * @return the links to the type parameters. duke@1: */ duke@1: public LinkOutput getTypeParameterLinks(LinkInfo linkInfo, boolean isClassLabel) { duke@1: LinkOutput output = getOutputInstance(); duke@1: Type[] vars; duke@1: if (linkInfo.executableMemberDoc != null) { duke@1: vars = linkInfo.executableMemberDoc.typeParameters(); duke@1: } else if (linkInfo.type != null && duke@1: linkInfo.type.asParameterizedType() != null){ duke@1: vars = linkInfo.type.asParameterizedType().typeArguments(); duke@1: } else if (linkInfo.classDoc != null){ duke@1: vars = linkInfo.classDoc.typeParameters(); duke@1: } else { duke@1: //Nothing to document. duke@1: return output; duke@1: } duke@1: if (((linkInfo.includeTypeInClassLinkLabel && isClassLabel) || duke@1: (linkInfo.includeTypeAsSepLink && ! isClassLabel) duke@1: ) duke@1: && vars.length > 0) { duke@1: linkInfo.displayLength += 1; duke@1: output.append(getLessThanString()); duke@1: for (int i = 0; i < vars.length; i++) { duke@1: if (i > 0) { duke@1: linkInfo.displayLength += 1; duke@1: output.append(","); duke@1: } duke@1: output.append(getTypeParameterLink(linkInfo, vars[i])); duke@1: } duke@1: linkInfo.displayLength += 1; duke@1: output.append(getGreaterThanString()); duke@1: } duke@1: return output; duke@1: } duke@1: duke@1: /** duke@1: * Return &lt;, which is used in type parameters. Override this duke@1: * if your doclet uses something different. duke@1: * duke@1: * @return return &lt;, which is used in type parameters. duke@1: */ duke@1: protected String getLessThanString() { duke@1: return "<"; duke@1: } duke@1: duke@1: /** duke@1: * Return &gt;, which is used in type parameters. Override this duke@1: * if your doclet uses something different. duke@1: * duke@1: * @return return &gt;, which is used in type parameters. duke@1: */ duke@1: protected String getGreaterThanString() { duke@1: return ">"; duke@1: } duke@1: }