1/*
2 * Copyright (c) 1998, 2012, 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.javadoc.main;
27
28import com.sun.javadoc.*;
29
30/**
31 * Documents a Serializable field defined by an ObjectStreamField.
32 * <pre>
33 * The class parses and stores the three serialField tag parameters:
34 *
35 * - field name
36 * - field type name
37 *      (fully-qualified or visible from the current import context)
38 * - description of the valid values for the field
39
40 * </pre>
41 * This tag is only allowed in the javadoc for the special member
42 * serialPersistentFields.
43 *
44 *  <p><b>This is NOT part of any supported API.
45 *  If you write code that depends on this, you do so at your own risk.
46 *  This code and its internal interfaces are subject to change or
47 *  deletion without notice.</b>
48 *
49 * @author Joe Fialli
50 * @author Neal Gafter
51 *
52 * @see java.io.ObjectStreamField
53 */
54@Deprecated
55class SerialFieldTagImpl
56    extends TagImpl
57    implements SerialFieldTag, Comparable<Object>
58{
59    //### These could be final, except that the constructor
60    //### does not set them directly.
61
62    private String fieldName;    // Required Argument 1 of serialField
63    private String fieldType;    // Required Argument 2 of serialField
64    private String description;  // Optional Remaining Arguments of serialField
65
66    private ClassDoc containingClass;   // Class containing serialPersistentField member
67    private ClassDoc fieldTypeDoc;      // ClassDocImpl of fieldType
68    private FieldDocImpl matchingField; // FieldDocImpl with same name as fieldName
69
70   /* Constructor. */
71   SerialFieldTagImpl(DocImpl holder, String name, String text) {
72        super(holder, name, text);
73        parseSerialFieldString();
74        if (holder instanceof MemberDoc) {
75            containingClass = ((MemberDocImpl)holder).containingClass();
76        }
77    }
78
79    /*
80     * The serialField tag is composed of three entities.
81     *
82     *   serialField  serializableFieldName serisliableFieldType
83     *                 description of field.
84     *
85     * The fieldName and fieldType must be legal Java Identifiers.
86     */
87    private void parseSerialFieldString() {
88        int len = text.length();
89        if (len == 0) {
90            return;
91        }
92
93        // if no white space found
94        /* Skip white space. */
95        int inx = 0;
96        int cp;
97        for (; inx < len; inx += Character.charCount(cp)) {
98             cp = text.codePointAt(inx);
99             if (!Character.isWhitespace(cp)) {
100                 break;
101             }
102        }
103
104        /* find first word. */
105        int first = inx;
106        int last = inx;
107        cp = text.codePointAt(inx);
108        if (! Character.isJavaIdentifierStart(cp)) {
109            docenv().warning(holder,
110                             "tag.serialField.illegal_character",
111                             new String(Character.toChars(cp)), text);
112            return;
113        }
114
115        for (inx += Character.charCount(cp); inx < len; inx += Character.charCount(cp)) {
116             cp = text.codePointAt(inx);
117             if (!Character.isJavaIdentifierPart(cp)) {
118                 break;
119             }
120        }
121
122        if (inx < len && ! Character.isWhitespace(cp = text.codePointAt(inx))) {
123            docenv().warning(holder,
124                             "tag.serialField.illegal_character",
125                             new String(Character.toChars(cp)), text);
126            return;
127        }
128
129        last = inx;
130        fieldName = text.substring(first, last);
131
132        /* Skip white space. */
133        for (; inx < len; inx += Character.charCount(cp)) {
134             cp = text.codePointAt(inx);
135             if (!Character.isWhitespace(cp)) {
136                 break;
137             }
138        }
139
140        /* find second word. */
141        first = inx;
142        last = inx;
143
144        for (; inx < len; inx += Character.charCount(cp)) {
145             cp = text.codePointAt(inx);
146             if (Character.isWhitespace(cp)) {
147                 break;
148             }
149        }
150        if (inx < len && ! Character.isWhitespace(cp = text.codePointAt(inx))) {
151            docenv().warning(holder,
152                             "tag.serialField.illegal_character",
153                             new String(Character.toChars(cp)), text);
154            return;
155        }
156        last = inx;
157        fieldType = text.substring(first, last);
158
159        /* Skip leading white space. Rest of string is description for serialField.*/
160        for (; inx < len; inx += Character.charCount(cp)) {
161             cp = text.codePointAt(inx);
162             if (!Character.isWhitespace(cp)) {
163                 break;
164             }
165        }
166        description = text.substring(inx);
167    }
168
169    /**
170     * return a key for sorting.
171     */
172    String key() {
173        return fieldName;
174    }
175
176    /*
177     * Optional. Link this serialField tag to its corrsponding
178     * field in the class. Note: there is no requirement that
179     * there be a field in the class that matches serialField tag.
180     */
181    void mapToFieldDocImpl(FieldDocImpl fd) {
182        matchingField = fd;
183    }
184
185    /**
186     * Return the serialziable field name.
187     */
188    public String fieldName() {
189        return fieldName;
190    }
191
192    /**
193     * Return the field type string.
194     */
195    public String fieldType() {
196        return fieldType;
197    }
198
199    /**
200     * Return the ClassDocImpl for field type.
201     *
202     * @returns null if no ClassDocImpl for field type is visible from
203     *          containingClass context.
204     */
205    public ClassDoc fieldTypeDoc() {
206        if (fieldTypeDoc == null && containingClass != null) {
207            fieldTypeDoc = containingClass.findClass(fieldType);
208        }
209        return fieldTypeDoc;
210    }
211
212    /**
213     * Return the corresponding FieldDocImpl for this SerialFieldTagImpl.
214     *
215     * @returns null if no matching FieldDocImpl.
216     */
217    FieldDocImpl getMatchingField() {
218        return matchingField;
219    }
220
221    /**
222     * Return the field comment. If there is no serialField comment, return
223     * javadoc comment of corresponding FieldDocImpl.
224     */
225    public String description() {
226        if (description.length() == 0 && matchingField != null) {
227
228            //check for javadoc comment of corresponding field.
229            Comment comment = matchingField.comment();
230            if (comment != null) {
231                return comment.commentText();
232            }
233        }
234        return description;
235    }
236
237    /**
238     * Return the kind of this tag.
239     */
240    public String kind() {
241        return "@serialField";
242    }
243
244    /**
245     * Convert this object to a string.
246     */
247    public String toString() {
248        return name + ":" + text;
249    }
250
251    /**
252     * Compares this Object with the specified Object for order.  Returns a
253     * negative integer, zero, or a positive integer as this Object is less
254     * than, equal to, or greater than the given Object.
255     * <p>
256     * Included to make SerialFieldTagImpl items java.lang.Comparable.
257     *
258     * @param   obj the <code>Object</code> to be compared.
259     * @return  a negative integer, zero, or a positive integer as this Object
260     *          is less than, equal to, or greater than the given Object.
261     * @exception ClassCastException the specified Object's type prevents it
262     *            from being compared to this Object.
263     * @since 1.2
264     */
265    public int compareTo(Object obj) {
266        return key().compareTo(((SerialFieldTagImpl)obj).key());
267    }
268}
269