duke@1: /* ohair@554: * Copyright (c) 1998, 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; duke@1: duke@1: import com.sun.tools.doclets.internal.toolkit.*; duke@1: import com.sun.javadoc.*; duke@1: import java.util.*; duke@1: duke@1: /** duke@1: * Process and manage grouping of packages, as specified by "-group" option on duke@1: * the command line. duke@1: *

duke@1: * For example, if user has used -group option as duke@1: * -group "Core Packages" "java.*" -group "CORBA Packages" "org.omg.*", then duke@1: * the packages specified on the command line will be grouped according to their duke@1: * names starting with either "java." or "org.omg.". All the other packages duke@1: * which do not fall in the user given groups, are grouped in default group, duke@1: * named as either "Other Packages" or "Packages" depending upon if "-group" duke@1: * option used or not at all used respectively. duke@1: *

duke@1: *

duke@1: * Also the packages are grouped according to the longest possible match of duke@1: * their names with the grouping information provided. For example, if there duke@1: * are two groups, like -group "Lang" "java.lang" and -group "Core" "java.*", duke@1: * will put the package java.lang in the group "Lang" and not in group "Core". duke@1: *

duke@1: * duke@1: * This code is not part of an API. duke@1: * It is implementation that is subject to change. duke@1: * Do not use it as an API duke@1: * duke@1: * @author Atul M Dambalkar duke@1: */ duke@1: public class Group { duke@1: duke@1: /** duke@1: * Map of regular expressions with the corresponding group name. duke@1: */ jjg@74: private Map regExpGroupMap = new HashMap(); duke@1: duke@1: /** duke@1: * List of regular expressions sorted according to the length. Regular duke@1: * expression with longest length will be first in the sorted order. duke@1: */ jjg@74: private List sortedRegExpList = new ArrayList(); duke@1: duke@1: /** duke@1: * List of group names in the same order as given on the command line. duke@1: */ jjg@74: private List groupList = new ArrayList(); duke@1: duke@1: /** duke@1: * Map of non-regular expressions(possible package names) with the duke@1: * corresponding group name. duke@1: */ jjg@74: private Map pkgNameGroupMap = new HashMap(); duke@1: duke@1: /** duke@1: * The global configuration information for this run. duke@1: */ duke@1: private final Configuration configuration; duke@1: duke@1: /** duke@1: * Since we need to sort the keys in the reverse order(longest key first), duke@1: * the compare method in the implementing class is doing the reverse duke@1: * comparison. duke@1: */ jjg@74: private static class MapKeyComparator implements Comparator { jjg@74: public int compare(String key1, String key2) { jjg@74: return key2.length() - key1.length(); duke@1: } duke@1: } duke@1: jjg@140: public Group(Configuration configuration) { duke@1: this.configuration = configuration; duke@1: } duke@1: duke@1: /** duke@1: * Depending upon the format of the package name provided in the "-group" duke@1: * option, generate two separate maps. There will be a map for mapping duke@1: * regular expression(only meta character allowed is '*' and that is at the duke@1: * end of the regular expression) on to the group name. And another map duke@1: * for mapping (possible) package names(if the name format doesen't contain duke@1: * meta character '*', then it is assumed to be a package name) on to the duke@1: * group name. This will also sort all the regular expressions found in the duke@1: * reverse order of their lengths, i.e. longest regular expression will be duke@1: * first in the sorted list. duke@1: * duke@1: * @param groupname The name of the group from -group option. duke@1: * @param pkgNameFormList List of the package name formats. duke@1: */ duke@1: public boolean checkPackageGroups(String groupname, duke@1: String pkgNameFormList) { duke@1: StringTokenizer strtok = new StringTokenizer(pkgNameFormList, ":"); duke@1: if (groupList.contains(groupname)) { duke@1: configuration.message.warning("doclet.Groupname_already_used", groupname); duke@1: return false; duke@1: } duke@1: groupList.add(groupname); duke@1: while (strtok.hasMoreTokens()) { duke@1: String id = strtok.nextToken(); duke@1: if (id.length() == 0) { duke@1: configuration.message.warning("doclet.Error_in_packagelist", groupname, pkgNameFormList); duke@1: return false; duke@1: } duke@1: if (id.endsWith("*")) { duke@1: id = id.substring(0, id.length() - 1); duke@1: if (foundGroupFormat(regExpGroupMap, id)) { duke@1: return false; duke@1: } duke@1: regExpGroupMap.put(id, groupname); duke@1: sortedRegExpList.add(id); duke@1: } else { duke@1: if (foundGroupFormat(pkgNameGroupMap, id)) { duke@1: return false; duke@1: } duke@1: pkgNameGroupMap.put(id, groupname); duke@1: } duke@1: } duke@1: Collections.sort(sortedRegExpList, new MapKeyComparator()); duke@1: return true; duke@1: } duke@1: duke@1: /** duke@1: * Search if the given map has given the package format. duke@1: * duke@1: * @param map Map to be searched. duke@1: * @param pkgFormat The pacakge format to search. duke@1: * duke@1: * @return true if package name format found in the map, else false. duke@1: */ mcimadamore@184: boolean foundGroupFormat(Map map, String pkgFormat) { duke@1: if (map.containsKey(pkgFormat)) { duke@1: configuration.message.error("doclet.Same_package_name_used", pkgFormat); duke@1: return true; duke@1: } duke@1: return false; duke@1: } duke@1: duke@1: /** duke@1: * Group the packages according the grouping information provided on the duke@1: * command line. Given a list of packages, search each package name in duke@1: * regular expression map as well as package name map to get the duke@1: * corresponding group name. Create another map with mapping of group name duke@1: * to the package list, which will fall under the specified group. If any duke@1: * package doesen't belong to any specified group on the comamnd line, then duke@1: * a new group named "Other Packages" will be created for it. If there are duke@1: * no groups found, in other words if "-group" option is not at all used, duke@1: * then all the packages will be grouped under group "Packages". duke@1: * duke@1: * @param packages Packages specified on the command line. duke@1: */ jjg@74: public Map> groupPackages(PackageDoc[] packages) { jjg@74: Map> groupPackageMap = new HashMap>(); duke@1: String defaultGroupName = duke@1: (pkgNameGroupMap.isEmpty() && regExpGroupMap.isEmpty())? duke@1: configuration.message.getText("doclet.Packages") : duke@1: configuration.message.getText("doclet.Other_Packages"); duke@1: // if the user has not used the default group name, add it duke@1: if (!groupList.contains(defaultGroupName)) { duke@1: groupList.add(defaultGroupName); duke@1: } duke@1: for (int i = 0; i < packages.length; i++) { duke@1: PackageDoc pkg = packages[i]; duke@1: String pkgName = pkg.name(); jjg@74: String groupName = pkgNameGroupMap.get(pkgName); duke@1: // if this package is not explicitly assigned to a group, duke@1: // try matching it to group specified by regular expression duke@1: if (groupName == null) { duke@1: groupName = regExpGroupName(pkgName); duke@1: } duke@1: // if it is in neither group map, put it in the default duke@1: // group duke@1: if (groupName == null) { duke@1: groupName = defaultGroupName; duke@1: } duke@1: getPkgList(groupPackageMap, groupName).add(pkg); duke@1: } duke@1: return groupPackageMap; duke@1: } duke@1: duke@1: /** duke@1: * Search for package name in the sorted regular expression duke@1: * list, if found return the group name. If not, return null. duke@1: * duke@1: * @param pkgName Name of package to be found in the regular duke@1: * expression list. duke@1: */ duke@1: String regExpGroupName(String pkgName) { duke@1: for (int j = 0; j < sortedRegExpList.size(); j++) { jjg@74: String regexp = sortedRegExpList.get(j); duke@1: if (pkgName.startsWith(regexp)) { jjg@74: return regExpGroupMap.get(regexp); duke@1: } duke@1: } duke@1: return null; duke@1: } duke@1: duke@1: /** duke@1: * For the given group name, return the package list, on which it is mapped. duke@1: * Create a new list, if not found. duke@1: * duke@1: * @param map Map to be searched for gorup name. duke@1: * @param groupname Group name to search. duke@1: */ jjg@74: List getPkgList(Map> map, String groupname) { jjg@74: List list = map.get(groupname); duke@1: if (list == null) { jjg@74: list = new ArrayList(); duke@1: map.put(groupname, list); duke@1: } duke@1: return list; duke@1: } duke@1: duke@1: /** duke@1: * Return the list of groups, in the same order as specified duke@1: * on the command line. duke@1: */ mcimadamore@184: public List getGroupList() { duke@1: return groupList; duke@1: } duke@1: }