FileDocCategorySizeDatePackage
Extern.javaAPI DocExample8371Wed Apr 19 11:17:10 BST 2000com.sun.tools.doclets.standard

Extern.java

/*
 * @(#)Extern.java	1.10 00/02/02
 *
 * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
 * 
 * This software is the proprietary information of Sun Microsystems, Inc.  
 * Use is subject to license terms.
 * 
 */

package com.sun.tools.doclets.standard;

import com.sun.tools.doclets.*;
import com.sun.javadoc.*;
import java.util.Map;
import java.util.HashMap;
import java.io.*;
import java.net.*;

/**
 * Process and manage "-link" and "-linkoffline" to external packages. The 
 * options "-link" and "-linkoffline" both depend on the fact that Javadoc now 
 * generates "package-list"(lists all the packages which are getting 
 * documented) file in the current or the destination directory, while
 * generating the documentation.
 *
 * @author Atul M Dambalkar
 * @author Robert Field
 */
public class Extern {

    /**
     * Map package names on to this object.
     */
    static private Map packageMap;

    /**
     * Package name, found in the "package-list" file in the {@link path}.
     */
    final String packageName;
 
    /**
     * The URL or the directory path at which the package documentation will be
     * avaliable.
     */
    final String path;

    /**
     * If given path is directory path then true else if it is a URL then false.
     */
    final boolean relative;

    /**
     * Constructor to build a Extern object and map it with the package name.
     * If the same package name is found in the map, then the first mapped
     * Extern object or offline location will be retained.
     *
     * @param packagename Package name found in the "package-list" file.
     * @param path        URL or Directory path from where the "package-list"
     * file is picked.
     * @param relative    True if path is URL, false if directory path.
     */
    Extern(String packageName, String path, boolean relative) {
        this.packageName = packageName;
        this.path = path;
        this.relative = relative;
        if (packageMap == null) {
            packageMap = new HashMap();
        }
        if (!packageMap.containsKey(packageName)) { // save the previous 
	  packageMap.put(packageName, this);        // mapped location
        }
    }

    /**
     * Get the "Extern" object associated with this package name.
     *
     * @param pkgname Package name.
     */
    public static Extern findPackage(String pkgName) {
        if (packageMap == null) {
            return null;
        }
        return (Extern)packageMap.get(pkgName);
    }

    /**
     * Build the extern package list from given URL or the directory path. 
     * Flag error if the "-link" or "-linkoffline" option is already used.
     * 
     * @param url        URL or Directory path.
     * @param pkglisturl This can be another URL for "pacakge-list" or ordinary
     * file.
     */
    public static boolean url(String url, String pkglisturl,
                              DocErrorReporter reporter) {
        String errMsg = composeExternPackageList(url, pkglisturl);
        if (errMsg != null) {
            reporter.printError(errMsg);
            return false;
        } else {
            return true;
        }
    } 
        
    /**
     * Adjusts the end file separator if it is missing from the URL or the 
     * directory path and depending upon the URL or file path, it fetches or 
     * reads the "package-list" file.
     *
     * @param url        URL or the directory path.
     * @param pkglisturl URL for the "package-list" file or the "package-list" 
     * file itself.
     */
    static String composeExternPackageList(String url, String pkglisturl) {
        url = adjustEndFileSeparator(url);
        pkglisturl = adjustEndFileSeparator(pkglisturl);
        if (pkglisturl.startsWith("http://") ||   
            pkglisturl.startsWith("file:")) {
            return fetchURLComposeExternPackageList(url, pkglisturl);
        } else {
            return readFileComposeExternPackageList(url, pkglisturl);
        }                   
    }

    /**
     * If the URL or Directory path is missing end file separator, add that.
     */
    static String adjustEndFileSeparator(String url) {
        String filesep = isRelativePath(url)? File.separator: "/";
        if (!url.endsWith(filesep)) {
            url += filesep; 
        }
        return url;
    }

    /**
     * Return true if it's a relative file path and does not start with 
     * "http://" or "file:" string.
     */
    static boolean isRelativePath(String url) {
        return !(url.startsWith("http://") || url.startsWith("file:"));
    }

    /**
     * Retrieve the text from the resource bundle.
     * 
     * @param prop Message key.
     * @param link Message argument.
     */
    private static String getText(String prop, String link) {
        return Standard.configuration().standardmessage.getText(prop, link);
    }

    /**
     * Retrieve the text from the resource bundle.
     * 
     * @param msg Message key.
     */
    private static String getText(String msg) {
        return Standard.configuration().standardmessage.getText(msg);
    }

    /**
     * Fetch the URL and read the "package-list" file.
     *
     * @param urlpath        Path to the packages.
     * @param pkglisturlpath URL or the path to the "package-list" file.
     */
    static String fetchURLComposeExternPackageList(String urlpath, 
                                                   String pkglisturlpath) {
        String link = pkglisturlpath + "package-list"; 
        try {
            boolean relative = isRelativePath(urlpath);
            readPackageList((new URL(link)).openStream(), urlpath, relative);
        } catch (MalformedURLException exc) {
            return getText("doclet.MalformedURL", link);
        } catch (IOException exc) {
            return getText("doclet.URL_error", link);
        } 
        return null;
    }

    /**
     * Read the "package-list" file which is available locally.
     *
     * @param urlpath URL or Directory path to hte packages.
     * @param relpath Path to the local "package-list" file.
     */
    static String readFileComposeExternPackageList(String urlpath, 
                                                   String relpath) {
        String link = relpath + "package-list";
        try {
            File file = new File(link);    
            if (file.exists() && file.canRead()) {
                boolean relative = isRelativePath(urlpath);
                readPackageList(new FileInputStream(file), urlpath, relative);
            } else {
                return getText("doclet.File_error", link);
            }
        } catch (FileNotFoundException exc) {
            return getText("doclet.File_error", link);
        } catch (IOException exc) {
            return getText("doclet.File_error", link);
        }
        return null;
    }
     
    /**               
     * Read the file "package-list" and for each package name found, create
     * Extern object and associate it with the package name in the map.
     *
     * @param input    InputStream from the "package-list" file.
     * @param path     URL or the directory path to the packages.
     * @param relative Is path relative?
     */
    static void readPackageList(InputStream input, String path, 
                                boolean relative)  
                         throws IOException {
        InputStreamReader in = new InputStreamReader(input);
        StringBuffer strbuf = new StringBuffer();
        try {
            int c;
            while ((c = in.read()) >= 0) {
                char ch = (char)c;
                if (ch == '\n' || ch == '\r') {
                    if (strbuf.length() > 0) {
                        String packname = strbuf.toString();
                        String packpath = path + 
                                      packname.replace('.', '/') + '/';
                        new Extern(packname, packpath, relative); 
                        strbuf.setLength(0);
                    }
                } else {
                    strbuf.append(ch);
                }
            }
        } finally {
            input.close();
        } 
    }     

    /**
     * String representation of "this" with packagename and the path.
     */
    public String toString() {
        return packageName + (relative? " -> " : " => ") + path;
    }
}