001: /*
002: * Copyright 1998-2004 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.tools.doclets.internal.toolkit.*;
029: import com.sun.javadoc.*;
030: import java.util.*;
031:
032: /**
033: * Process and manage grouping of packages, as specified by "-group" option on
034: * the command line.
035: * <p>
036: * For example, if user has used -group option as
037: * -group "Core Packages" "java.*" -group "CORBA Packages" "org.omg.*", then
038: * the packages specified on the command line will be grouped according to their
039: * names starting with either "java." or "org.omg.". All the other packages
040: * which do not fall in the user given groups, are grouped in default group,
041: * named as either "Other Packages" or "Packages" depending upon if "-group"
042: * option used or not at all used respectively.
043: * </p>
044: * <p>
045: * Also the packages are grouped according to the longest possible match of
046: * their names with the grouping information provided. For example, if there
047: * are two groups, like -group "Lang" "java.lang" and -group "Core" "java.*",
048: * will put the package java.lang in the group "Lang" and not in group "Core".
049: * </p>
050: *
051: * This code is not part of an API.
052: * It is implementation that is subject to change.
053: * Do not use it as an API
054: *
055: * @author Atul M Dambalkar
056: */
057: public class Group {
058:
059: private static Group instance;
060:
061: /**
062: * Map of regular expressions with the corresponding group name.
063: */
064: private Map regExpGroupMap = new HashMap();
065:
066: /**
067: * List of regular expressions sorted according to the length. Regular
068: * expression with longest length will be first in the sorted order.
069: */
070: private List sortedRegExpList = new ArrayList();
071:
072: /**
073: * List of group names in the same order as given on the command line.
074: */
075: private List groupList = new ArrayList();
076:
077: /**
078: * Map of non-regular expressions(possible package names) with the
079: * corresponding group name.
080: */
081: private Map pkgNameGroupMap = new HashMap();
082:
083: /**
084: * The global configuration information for this run.
085: */
086: private final Configuration configuration;
087:
088: /**
089: * Since we need to sort the keys in the reverse order(longest key first),
090: * the compare method in the implementing class is doing the reverse
091: * comparison.
092: */
093: private static class MapKeyComparator implements Comparator {
094: public int compare(Object key1, Object key2) {
095: return ((String) key2).length() - ((String) key1).length();
096: }
097: }
098:
099: private Group(Configuration configuration) {
100: this .configuration = configuration;
101: }
102:
103: public static Group getInstance(Configuration configuration) {
104: if (instance == null) {
105: instance = new Group(configuration);
106: }
107: return instance;
108: }
109:
110: /**
111: * Depending upon the format of the package name provided in the "-group"
112: * option, generate two separate maps. There will be a map for mapping
113: * regular expression(only meta character allowed is '*' and that is at the
114: * end of the regular expression) on to the group name. And another map
115: * for mapping (possible) package names(if the name format doesen't contain
116: * meta character '*', then it is assumed to be a package name) on to the
117: * group name. This will also sort all the regular expressions found in the
118: * reverse order of their lengths, i.e. longest regular expression will be
119: * first in the sorted list.
120: *
121: * @param groupname The name of the group from -group option.
122: * @param pkgNameFormList List of the package name formats.
123: */
124: public boolean checkPackageGroups(String groupname,
125: String pkgNameFormList) {
126: StringTokenizer strtok = new StringTokenizer(pkgNameFormList,
127: ":");
128: if (groupList.contains(groupname)) {
129: configuration.message.warning(
130: "doclet.Groupname_already_used", groupname);
131: return false;
132: }
133: groupList.add(groupname);
134: while (strtok.hasMoreTokens()) {
135: String id = strtok.nextToken();
136: if (id.length() == 0) {
137: configuration.message.warning(
138: "doclet.Error_in_packagelist", groupname,
139: pkgNameFormList);
140: return false;
141: }
142: if (id.endsWith("*")) {
143: id = id.substring(0, id.length() - 1);
144: if (foundGroupFormat(regExpGroupMap, id)) {
145: return false;
146: }
147: regExpGroupMap.put(id, groupname);
148: sortedRegExpList.add(id);
149: } else {
150: if (foundGroupFormat(pkgNameGroupMap, id)) {
151: return false;
152: }
153: pkgNameGroupMap.put(id, groupname);
154: }
155: }
156: Collections.sort(sortedRegExpList, new MapKeyComparator());
157: return true;
158: }
159:
160: /**
161: * Search if the given map has given the package format.
162: *
163: * @param map Map to be searched.
164: * @param pkgFormat The pacakge format to search.
165: *
166: * @return true if package name format found in the map, else false.
167: */
168: boolean foundGroupFormat(Map map, String pkgFormat) {
169: if (map.containsKey(pkgFormat)) {
170: configuration.message.error(
171: "doclet.Same_package_name_used", pkgFormat);
172: return true;
173: }
174: return false;
175: }
176:
177: /**
178: * Group the packages according the grouping information provided on the
179: * command line. Given a list of packages, search each package name in
180: * regular expression map as well as package name map to get the
181: * corresponding group name. Create another map with mapping of group name
182: * to the package list, which will fall under the specified group. If any
183: * package doesen't belong to any specified group on the comamnd line, then
184: * a new group named "Other Packages" will be created for it. If there are
185: * no groups found, in other words if "-group" option is not at all used,
186: * then all the packages will be grouped under group "Packages".
187: *
188: * @param packages Packages specified on the command line.
189: */
190: public Map groupPackages(PackageDoc[] packages) {
191: Map groupPackageMap = new HashMap();
192: String defaultGroupName = (pkgNameGroupMap.isEmpty() && regExpGroupMap
193: .isEmpty()) ? configuration.message
194: .getText("doclet.Packages") : configuration.message
195: .getText("doclet.Other_Packages");
196: // if the user has not used the default group name, add it
197: if (!groupList.contains(defaultGroupName)) {
198: groupList.add(defaultGroupName);
199: }
200: for (int i = 0; i < packages.length; i++) {
201: PackageDoc pkg = packages[i];
202: String pkgName = pkg.name();
203: String groupName = (String) pkgNameGroupMap.get(pkgName);
204: // if this package is not explicitly assigned to a group,
205: // try matching it to group specified by regular expression
206: if (groupName == null) {
207: groupName = regExpGroupName(pkgName);
208: }
209: // if it is in neither group map, put it in the default
210: // group
211: if (groupName == null) {
212: groupName = defaultGroupName;
213: }
214: getPkgList(groupPackageMap, groupName).add(pkg);
215: }
216: return groupPackageMap;
217: }
218:
219: /**
220: * Search for package name in the sorted regular expression
221: * list, if found return the group name. If not, return null.
222: *
223: * @param pkgName Name of package to be found in the regular
224: * expression list.
225: */
226: String regExpGroupName(String pkgName) {
227: for (int j = 0; j < sortedRegExpList.size(); j++) {
228: String regexp = (String) sortedRegExpList.get(j);
229: if (pkgName.startsWith(regexp)) {
230: return (String) regExpGroupMap.get(regexp);
231: }
232: }
233: return null;
234: }
235:
236: /**
237: * For the given group name, return the package list, on which it is mapped.
238: * Create a new list, if not found.
239: *
240: * @param map Map to be searched for gorup name.
241: * @param groupname Group name to search.
242: */
243: List getPkgList(Map map, String groupname) {
244: List list = (List) map.get(groupname);
245: if (list == null) {
246: list = new ArrayList();
247: map.put(groupname, list);
248: }
249: return list;
250: }
251:
252: /**
253: * Return the list of groups, in the same order as specified
254: * on the command line.
255: */
256: public List getGroupList() {
257: return groupList;
258: }
259: }
|