FileDocCategorySizeDatePackage
APIRepository.javaAPI DocGlassfish v2 API17616Fri May 04 22:33:26 BST 2007com.sun.enterprise.tools.verifier.apiscan.stdapis

APIRepository.java

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 * 
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License. You can obtain
 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 * 
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [year]
 * [name of copyright owner]"
 * 
 * Contributor(s):
 * 
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

/*
 * APIHelper.java
 *
 * Created on September 22, 2004, 10:23 AM
 */

package com.sun.enterprise.tools.verifier.apiscan.stdapis;

import java.io.InputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.StringTokenizer;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;

/**
 * This class represents a repository of APIs. It is backed by a XML file
 * with a predefined schema. This class is resoponsible for parsing the
 * XML file and getting populated by the information available in that file.
 * In verifier, this class is used in conjunction with an XML file where all
 * the standard APIs are listed along with their respective version number.
 * Refer to standard-apis.xml file to see how we list APIs in that file.
 * 
 * @author Sanjeeb.Sahoo@Sun.COM
 */
public class APIRepository {
    private static Logger logger = Logger.getLogger("apiscan.stdapis"); // NOI18N
    private static String myClsName = "APIRepository"; // NOI18N
    private HashMap<String, API> apis = new HashMap<String, API>();
    //singleton
    private static APIRepository me;

    /**
     * Return the singleton instance.
     */
    public static APIRepository Instance() {
        assert(me != null);
        return me;
    }

    /**
     * Initialize the singleton instance.
     *
     * @param fileName An XML file which contains the details of APIs.
     */
    public synchronized static void Initialize(String fileName)
            throws Exception {
        logger.logp(Level.FINE, myClsName, "Initialize", fileName); // NOI18N
        //Pl refer to bug#6174887
//        assert(me==null);
//        if(me==null){
        me = new APIRepository(fileName);
//        }else throw new RuntimeException("Already Initialized");
    }

    /**
     * This method is used to find out if a particular class is part of 
     * a standard API or not. e.g. to find out if an EJB 2.0 application is 
     * allowed to use javax.ejb.Timer.class, call this method as 
     * <blockquote><pre>
     * isClassPartOf("javax.ejb.Timer","ejb_jar_2.0")
     * </pre></blockquote>
     *
     * @param class_name name of the class (in external class name format)
     * @param api_name_version is the name of the API along with version. It
     * must already be defined in the XML file.
     * 
     * @return true iff the given class is part of this API.
     */
    public boolean isClassPartOf(String class_name, String api_name_version) {
        if (getClassesFor(api_name_version).contains(class_name)) {
            return true;
        } else if (getPackagesFor(api_name_version).
                contains(getPackageName(class_name))) {
            return true;
        } else {
            for (String pattern : getPatternsFor(api_name_version)) {
                if (class_name.startsWith(pattern)) {
                    return true;
                }
            }
        }
        return false;
    }
    
    /**
     * This method is used to find out if a particular package is part of 
     * a standard API or not. e.g. to find out if an appclient (v 1.4) is 
     * allowed to import javax.persistence.* , call this method as 
     * <blockquote><pre>
     * isPackagePartOf("javax.persistence","appclient_1.4")
     * </pre></blockquote>
     *
     * @param pkg_name name of the package
     * @param api_name_version is the name of the API along with version. It
     * must already be defined in the XML file.
     * 
     * @return true iff the given package is part of this API.
     */
    public boolean isPackagePartOf(String pkg_name, String api_name_version) {
        if (getPackagesFor(api_name_version).contains(pkg_name)) {
            return true;
        } else {
            for (String pattern : getPatternsFor(api_name_version)) {
                if (pkg_name.startsWith(pattern)) {
                    return true;
                }
            }
        }
        return false;
    }
    
    protected Collection<String> getPackagesFor(String api_name_version) {
        return ((API) apis.get(api_name_version)).getPackages();
    }

    protected Collection<String> getPatternsFor(String api_name_version) {
        return ((API) apis.get(api_name_version)).getPatterns();
    }

    protected Collection<String> getClassesFor(String api_name_version) {
        return ((API) apis.get(api_name_version)).getClasses();
    }

    public String toString() {
        StringBuffer sb = new StringBuffer();
        for (Iterator i = apis.values().iterator(); i.hasNext();) {
            sb.append("\n").append(i.next().toString()); // NOI18N
        }
        return sb.toString();
    }

    private APIRepository(String fileName) throws Exception {
        logger.entering(myClsName, "init<>", fileName); // NOI18N
        final File file = new File(fileName);
        Document d = getDocumentBuilder().parse(file);
        traverseTree(d.getDocumentElement());
    }
    
    private DocumentBuilder getDocumentBuilder() throws Exception {
        DocumentBuilderFactory bf = DocumentBuilderFactory.newInstance();
        bf.setValidating(true);
        bf.setIgnoringComments(false);
        bf.setIgnoringElementContentWhitespace(true);
        bf.setCoalescing(true);
        bf.setNamespaceAware(true);
        bf.setAttribute(
                "http://java.sun.com/xml/jaxp/properties/schemaLanguage", // NOI18N
                "http://www.w3.org/2001/XMLSchema"); // NOI18N
        DocumentBuilder builder = bf.newDocumentBuilder();
        builder.setErrorHandler(new DefaultHandler() {
            public void error(SAXParseException e) throws SAXException {
                throw e;
            }
        });
        return builder;
    }

    private void traverseTree(Node node) {
        if (node == null) {
            return;
        }
        if (node.getNodeType() == Node.ELEMENT_NODE) {
            Element e = (Element) node;
            String tagName = e.getTagName();
            if (tagName.equals("api")) { // NOI18N
                API a = new API(e);
                apis.put(a.name_version, a);
            }
            NodeList childNodes = node.getChildNodes();
            for (int i = 0; i < childNodes.getLength(); i++) {
                traverseTree(childNodes.item(i));
            }
        }
    }

    //return java.util for java.util.Map$Entry
    private static String getPackageName(String externalClassName) {
        int idx = externalClassName.lastIndexOf('.');
        if (idx != -1) {
            return externalClassName.substring(0, idx);
        } else
            return "";
    }

    class APIRef {
        private String api_name_version;

        public APIRef(Element node) {
            if (node.getTagName().equals("api_ref")) { // NOI18N
                api_name_version = node.getAttribute("api_name_version"); // NOI18N
            } else
                throw new IllegalArgumentException(node.toString());
        }

        public APIRef(String api_name_version) {
            this.api_name_version = api_name_version;
        }

        public API deref() {
            API result = (API) apis.get(api_name_version);
            if (result == null)
                throw new NullPointerException(
                        "No API with name_version [" + api_name_version + "]"); // NOI18N
            return result;
        }
    }

    class API {
        private String name_version;
        private ArrayList<APIRef> apiRefs = new ArrayList<APIRef>();
        ArrayList<String> packages = new ArrayList<String>(), patterns = new ArrayList<String>(), classes = new ArrayList<String>();

        public API(Element node) {
            if (node.getTagName().equals("api")) { // NOI18N
                name_version = node.getAttribute("name_version"); // NOI18N
                NodeList refNodes = node.getElementsByTagName("api_ref"); // NOI18N
                for (int loopIndex = 0;
                     loopIndex < refNodes.getLength(); loopIndex++) {
                    apiRefs.add(new APIRef((Element) refNodes.item(loopIndex)));
                }
                NodeList pkgsNodes = node.getElementsByTagName("packages"); // NOI18N
                for (int i = 0; i < pkgsNodes.getLength(); ++i) {
                    Element pkgsNode = (Element) pkgsNodes.item(i);
                    NodeList children = pkgsNode.getChildNodes();
                    for (int j = 0; j < children.getLength(); j++) {
                        Node next = children.item(j);
                        if (next.getNodeType() == Node.TEXT_NODE) {
                            String names = next.getNodeValue().trim();
                            for (StringTokenizer st = new StringTokenizer(
                                    names);
                                 st.hasMoreTokens();) {
                                packages.add(st.nextToken());
                            }
                        }
                    }
                }
                NodeList patternsNodes = node.getElementsByTagName("patterns"); // NOI18N
                for (int i = 0; i < patternsNodes.getLength(); ++i) {
                    Element patternsNode = (Element) patternsNodes.item(i);
                    NodeList children = patternsNode.getChildNodes();
                    for (int j = 0; j < children.getLength(); j++) {
                        Node next = children.item(j);
                        if (next.getNodeType() == Node.TEXT_NODE) {
                            String names = next.getNodeValue().trim();
                            for (StringTokenizer st = new StringTokenizer(
                                    names);
                                 st.hasMoreTokens();) {
                                patterns.add(st.nextToken());
                            }
                        }
                    }
                }
                NodeList classesNodes = node.getElementsByTagName("classes"); // NOI18N
                for (int i = 0; i < classesNodes.getLength(); ++i) {
                    Element classesNode = (Element) classesNodes.item(i);
                    String package_name = classesNode.getAttribute("package") // NOI18N
                            .trim();
                    NodeList children = classesNode.getChildNodes();
                    for (int j = 0; j < children.getLength(); j++) {
                        Node next = children.item(j);
                        if (next.getNodeType() == Node.TEXT_NODE) {
                            String names = next.getNodeValue().trim();
                            for (StringTokenizer st = new StringTokenizer(
                                    names);
                                 st.hasMoreTokens();) {
                                String clsName = package_name + "." + // NOI18N
                                        st.nextToken();
                                classes.add(clsName);
                            }
                        }
                    }
                }
            } else {
                throw new IllegalArgumentException(node.toString());
            }
        }//constructor

        public Collection<String> getPackages() {
            ArrayList<String> results = new ArrayList<String>();
            for (Iterator i = apiRefs.iterator(); i.hasNext();) {
                results.addAll(((APIRef) i.next()).deref().getPackages());
            }
            results.addAll(packages);
            return results;
        }

        public Collection<String> getPatterns() {
            ArrayList<String> results = new ArrayList<String>();
            for (Iterator i = apiRefs.iterator(); i.hasNext();) {
                results.addAll(((APIRef) i.next()).deref().getPatterns());
            }
            results.addAll(patterns);
            return results;
        }

        public Collection<String> getClasses() {
            ArrayList<String> results = new ArrayList<String>();
            for (Iterator i = apiRefs.iterator(); i.hasNext();) {
                results.addAll(((APIRef) i.next()).deref().getClasses());
            }
            results.addAll(classes);
            return results;
        }

        public String toString() {
            StringBuffer sb = new StringBuffer();
            sb.append("<api name_version=\"" + name_version + "\">"); // NOI18N
            sb.append("\n\t<classes>"); // NOI18N
            for (Iterator i = getClasses().iterator(); i.hasNext();) sb.append(
                    "\n\t\t") // NOI18N
                    .append(i.next().toString());
            sb.append("\n\t</classes>"); // NOI18N
            sb.append("\n\t<packages>"); // NOI18N
            for (Iterator i = getPackages().iterator(); i.hasNext();) sb.append(
                    "\n\t\t") // NOI18N
                    .append(i.next().toString());
            sb.append("\n\t</packages>"); // NOI18N
            sb.append("\n\t<patterns>"); // NOI18N
            for (Iterator i = getPatterns().iterator(); i.hasNext();) sb.append(
                    "\n\t\t") // NOI18N
                    .append(i.next().toString());
            sb.append("\n\t</patterns>"); // NOI18N
            sb.append("\n</api>"); // NOI18N
            return sb.toString();
        }
    }//class API

    public static void main(String[] args) {
        if (args.length < 1) {
            usage();
        }
        Logger logger = Logger.getLogger("apiscan.stdapis"); // NOI18N
        try {
            APIRepository.Initialize(args[0]);
            APIRepository apiRep = APIRepository.Instance();
            switch(args.length) {
                case 1:
                    System.out.println(apiRep);
                    break;
                case 2:
                    System.out.println(apiRep.apis.get(args[1]));
                    break;
                case 3:
                    System.out.println(apiRep.isClassPartOf(args[2], args[1]));
                    break;
                default:
                    usage();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    private static void usage(){
        System.out.println(
                "Usage: java " + APIRepository.class.getName() + // NOI18N
                " <file_name> [api_name_version] [class_name]"); // NOI18N
        System.out.println("\nExamples:\n"); // NOI18N
        System.out.println(
                "java " + APIRepository.class.getName() + // NOI18N
                " src/standard-apis.xml ejb_jar_2.0 javax.ejb.Timer"); // NOI18N
        System.out.println("The above command prints true if javax.ejb.Timer is part of ejb_api_2.0 API.\n"); // NOI18N
        System.out.println(
                "java " + APIRepository.class.getName() + // NOI18N
                " src/standard-apis.xml ejb_jar_2.0"); // NOI18N
        System.out.println("The above command prints details about all classes and packages for ejb_api_2.0 API.\n"); // NOI18N
        System.out.println(
                "java " + APIRepository.class.getName() + // NOI18N
                " src/standard-apis.xml"); // NOI18N
        System.out.println("The above command prints details about all APIs.\n"); // NOI18N
        System.exit(1);
    }
}//class APIRespository