/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright (c) 1997-2010 Oracle and/or its affiliates. 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_1_1.html * or packager/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 packager/legal/LICENSE.txt. * * GPL Classpath Exception: * Oracle designates this particular file as subject to the "Classpath" * exception as provided by Oracle in the GPL Version 2 section of the License * file that accompanied this code. * * Modifications: * If applicable, add the following below the License Header, with the fields * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyright [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"); } /** * Initialize the singleton instance. * * @param is InputStream for an XML file which contains the details of APIs. */ public synchronized static void Initialize(InputStream is) throws Exception { logger.logp(Level.FINE, myClsName, "Initialize", is.toString()); // NOI18N //Pl refer to bug#6174887 // assert(me==null); // if(me==null){ me = new APIRepository(is); // }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 APIRepository(InputStream is) throws Exception { logger.entering(myClsName, "init<>", is.toString()); // NOI18N Document d = getDocumentBuilder().parse(is); traverseTree(d.getDocumentElement()); } private DocumentBuilder getDocumentBuilder() throws Exception { DocumentBuilderFactory bf = DocumentBuilderFactory.newInstance(); bf.setValidating(false); 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(); } 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