1/*
2 * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.sun.tools.doclets.internal.toolkit.util.links;
27
28import com.sun.javadoc.*;
29import com.sun.tools.doclets.internal.toolkit.Content;
30
31/**
32 * A factory that constructs links from given link information.
33 *
34 *  <p><b>This is NOT part of any supported API.
35 *  If you write code that depends on this, you do so at your own risk.
36 *  This code and its internal interfaces are subject to change or
37 *  deletion without notice.</b>
38 *
39 * @author Jamie Ho
40 * @since 1.5
41 */
42@Deprecated
43public abstract class LinkFactory {
44
45    /**
46     * Return an empty instance of a content object.
47     *
48     * @return an empty instance of a content object.
49     */
50    protected abstract Content newContent();
51
52    /**
53     * Constructs a link from the given link information.
54     *
55     * @param linkInfo the information about the link.
56     * @return the output of the link.
57     */
58    public Content getLink(LinkInfo linkInfo) {
59        if (linkInfo.type != null) {
60            Type type = linkInfo.type;
61            Content link = newContent();
62            if (type.isPrimitive()) {
63                //Just a primitive.
64                link.addContent(type.typeName());
65            } else if (type.asAnnotatedType() != null && type.dimension().length() == 0) {
66                link.addContent(getTypeAnnotationLinks(linkInfo));
67                linkInfo.type = type.asAnnotatedType().underlyingType();
68                link.addContent(getLink(linkInfo));
69                return link;
70            } else if (type.asWildcardType() != null) {
71                //Wildcard type.
72                linkInfo.isTypeBound = true;
73                link.addContent("?");
74                WildcardType wildcardType = type.asWildcardType();
75                Type[] extendsBounds = wildcardType.extendsBounds();
76                for (int i = 0; i < extendsBounds.length; i++) {
77                    link.addContent(i > 0 ? ", " : " extends ");
78                    setBoundsLinkInfo(linkInfo, extendsBounds[i]);
79                    link.addContent(getLink(linkInfo));
80                }
81                Type[] superBounds = wildcardType.superBounds();
82                for (int i = 0; i < superBounds.length; i++) {
83                    link.addContent(i > 0 ? ", " : " super ");
84                    setBoundsLinkInfo(linkInfo, superBounds[i]);
85                    link.addContent(getLink(linkInfo));
86                }
87            } else if (type.asTypeVariable()!= null) {
88                link.addContent(getTypeAnnotationLinks(linkInfo));
89                linkInfo.isTypeBound = true;
90                //A type variable.
91                Doc owner = type.asTypeVariable().owner();
92                if ((! linkInfo.excludeTypeParameterLinks) &&
93                        owner instanceof ClassDoc) {
94                    linkInfo.classDoc = (ClassDoc) owner;
95                    Content label = newContent();
96                    label.addContent(type.typeName());
97                    linkInfo.label = label;
98                    link.addContent(getClassLink(linkInfo));
99                } else {
100                    //No need to link method type parameters.
101                    link.addContent(type.typeName());
102                }
103
104                Type[] bounds = type.asTypeVariable().bounds();
105                if (! linkInfo.excludeTypeBounds) {
106                    linkInfo.excludeTypeBounds = true;
107                    for (int i = 0; i < bounds.length; i++) {
108                        link.addContent(i > 0 ? " & " : " extends ");
109                        setBoundsLinkInfo(linkInfo, bounds[i]);
110                        link.addContent(getLink(linkInfo));
111                    }
112                }
113            } else if (type.asClassDoc() != null) {
114                //A class type.
115                if (linkInfo.isTypeBound &&
116                        linkInfo.excludeTypeBoundsLinks) {
117                    //Since we are excluding type parameter links, we should not
118                    //be linking to the type bound.
119                    link.addContent(type.typeName());
120                    link.addContent(getTypeParameterLinks(linkInfo));
121                    return link;
122                } else {
123                    linkInfo.classDoc = type.asClassDoc();
124                    link = newContent();
125                    link.addContent(getClassLink(linkInfo));
126                    if (linkInfo.includeTypeAsSepLink) {
127                        link.addContent(getTypeParameterLinks(linkInfo, false));
128                    }
129                }
130            }
131
132            if (linkInfo.isVarArg) {
133                if (type.dimension().length() > 2) {
134                    //Javadoc returns var args as array.
135                    //Strip out the first [] from the var arg.
136                    link.addContent(type.dimension().substring(2));
137                }
138                link.addContent("...");
139            } else {
140                while (type != null && type.dimension().length() > 0) {
141                    if (type.asAnnotatedType() != null) {
142                        linkInfo.type = type;
143                        link.addContent(" ");
144                        link.addContent(getTypeAnnotationLinks(linkInfo));
145                        link.addContent("[]");
146                        type = type.asAnnotatedType().underlyingType().getElementType();
147                    } else {
148                        link.addContent("[]");
149                        type = type.getElementType();
150                    }
151                }
152                linkInfo.type = type;
153                Content newLink = newContent();
154                newLink.addContent(getTypeAnnotationLinks(linkInfo));
155                newLink.addContent(link);
156                link = newLink;
157            }
158            return link;
159        } else if (linkInfo.classDoc != null) {
160            //Just a class link
161            Content link = newContent();
162            link.addContent(getClassLink(linkInfo));
163            if (linkInfo.includeTypeAsSepLink) {
164                link.addContent(getTypeParameterLinks(linkInfo, false));
165            }
166            return link;
167        } else {
168            return null;
169        }
170    }
171
172    private void setBoundsLinkInfo(LinkInfo linkInfo, Type bound) {
173        linkInfo.classDoc = null;
174        linkInfo.label = null;
175        linkInfo.type = bound;
176    }
177
178    /**
179     * Return the link to the given class.
180     *
181     * @param linkInfo the information about the link to construct.
182     *
183     * @return the link for the given class.
184     */
185    protected abstract Content getClassLink(LinkInfo linkInfo);
186
187    /**
188     * Return the link to the given type parameter.
189     *
190     * @param linkInfo     the information about the link to construct.
191     * @param typeParam the type parameter to link to.
192     */
193    protected abstract Content getTypeParameterLink(LinkInfo linkInfo,
194        Type typeParam);
195
196    protected abstract Content getTypeAnnotationLink(LinkInfo linkInfo,
197            AnnotationDesc annotation);
198
199    /**
200     * Return the links to the type parameters.
201     *
202     * @param linkInfo     the information about the link to construct.
203     * @return the links to the type parameters.
204     */
205    public Content getTypeParameterLinks(LinkInfo linkInfo) {
206        return getTypeParameterLinks(linkInfo, true);
207    }
208
209    /**
210     * Return the links to the type parameters.
211     *
212     * @param linkInfo     the information about the link to construct.
213     * @param isClassLabel true if this is a class label.  False if it is
214     *                     the type parameters portion of the link.
215     * @return the links to the type parameters.
216     */
217    public Content getTypeParameterLinks(LinkInfo linkInfo, boolean isClassLabel) {
218        Content links = newContent();
219        Type[] vars;
220        if (linkInfo.executableMemberDoc != null) {
221            vars = linkInfo.executableMemberDoc.typeParameters();
222        } else if (linkInfo.type != null &&
223                linkInfo.type.asParameterizedType() != null){
224            vars =  linkInfo.type.asParameterizedType().typeArguments();
225        } else if (linkInfo.classDoc != null){
226            vars = linkInfo.classDoc.typeParameters();
227        } else {
228            //Nothing to document.
229            return links;
230        }
231        if (((linkInfo.includeTypeInClassLinkLabel && isClassLabel) ||
232             (linkInfo.includeTypeAsSepLink && ! isClassLabel)
233              )
234            && vars.length > 0) {
235            links.addContent("<");
236            for (int i = 0; i < vars.length; i++) {
237                if (i > 0) {
238                    links.addContent(",");
239                }
240                links.addContent(getTypeParameterLink(linkInfo, vars[i]));
241            }
242            links.addContent(">");
243        }
244        return links;
245    }
246
247    public Content getTypeAnnotationLinks(LinkInfo linkInfo) {
248        Content links = newContent();
249        if (linkInfo.type.asAnnotatedType() == null)
250            return links;
251        AnnotationDesc[] annotations = linkInfo.type.asAnnotatedType().annotations();
252        for (int i = 0; i < annotations.length; i++) {
253            if (i > 0) {
254                links.addContent(" ");
255            }
256            links.addContent(getTypeAnnotationLink(linkInfo, annotations[i]));
257        }
258
259        links.addContent(" ");
260        return links;
261    }
262}
263