com.sun.enterprise.tools.verifier.apiscan.classfile.ClosureCompilerImpl Maven / Gradle / Ivy
/*
* 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.
*/
package com.sun.enterprise.tools.verifier.apiscan.classfile;
import java.util.*;
import java.util.logging.Logger;
import java.io.IOException;
import java.io.File;
/**
* This is single most important class of the apiscan package. This class is
* used to compute the complete closure of a set of classes. It uses {@link
* ClassFile} to find out dependencies of a class. For each references class
* name, it loads the corresponding ClassFile using the ClassFileLoader passed
* to it in constructor. Then it recurssively computes the dependencies until it
* visits either Java primitive classes or the class name matches the exclude
* list. Example of using this class is given below...
*
* String classpath="your own classpath";
* ClassFileLoader cfl=ClassFileLoaderFactory.newInstance(new
* Object[]{classpath});
* ClosureCompilerImpl cc=new ClosureCompilerImpl(cfl);
* cc.addExcludePattern("java.");//exclude all classes that start with java.
* Most of the J2SE classes will be excluded thus.
* cc.addExcludePattern("javax.");//Most of the J2EE classes can be excluded
* like this.
* cc.addExcludePackage("org.omg.CORBA");//Exclude classes whose package name is
* org.omg.CORBA
* cc.addExcludeClass("mypackage.Foo");//Exclude class whose name is
* myPackage.Foo
* boolean successful=cc.buildClosure("a.b.MyEjb");
* successful=cc.buildClosure("a.b.YourEjb") && successful; //note the order of
* &&.
* Collection closure=cc.getClosure();//now closure contains the union of
* closure for the two classes.
* Map failed=cc.getFailed();//now failure contains the union of failures for
* the two classes.
* cc.reset();//clear the results collected so far so that we can start afresh.
* //Now you can again start computing closure of another set of classes.
* //The excluded stuff are still valid.
*
*
* @author [email protected]
*/
public class ClosureCompilerImpl implements ClosureCompiler {
/*
* BRIDGE design pattern.
* This is an abstraction. It delegates to an implementation.
* It is bound to an implementation at runtime. See the constructor.
*/
/**
* an implementation to whom this abstraction delegates.
* refer to bridge design pattern.
*/
private ClosureCompilerImplBase imp;
private static String resourceBundleName = "com.sun.enterprise.tools.verifier.apiscan.LocalStrings";
private static Logger logger = Logger.getLogger("apiscan.classfile", resourceBundleName); // NOI18N
private static final String myClassName = "ClosureCompilerImpl"; // NOI18N
/**
* @param loader the ClassFileLoader that is used to load the referenced
* classes.
*/
public ClosureCompilerImpl(ClassFileLoader loader) {
/*
* See how it binds to a runtime implementation
* TODO: Ideally we should introduce an AbstractFactory for
* both ClassFileLoader & ClassClosureCompiler product types.
*/
if(loader instanceof ASMClassFileLoader){
imp = new ASMClosureCompilerImpl(loader);
} else if(loader instanceof BCELClassFileLoader ||
loader instanceof BCELClassFileLoader1) {
imp = new BCELClosureCompilerImpl(loader);
} else {
throw new RuntimeException("Unknown loader type [" + loader + "]");
}
}
/**
* I don't expect this constructor to be used. Only defined for
* testing purpose.
* @param imp the implementation in the bridge design pattern.
*/
public ClosureCompilerImpl(ClosureCompilerImplBase imp) {
this.imp = imp;
}
/**
* @param className the class name to be excluded from closure
* computation. It is in the external class name format
* (i.e. java.util.Map$Entry instead of java.util.Map.Entry).
* When the closure compiler sees a class matches this
* name, it does not try to compute its closure any
* more. It merely adds this name to the closure. So the
* final closure will contain this class name, but not
* its dependencies.
*/
public void addExcludedClass(String className) {
imp.addExcludedClass(className);
}
//takes in external format, i.e. java.util
/**
* @param pkgName the package name of classes to be excluded from
* closure computation. It is in the external format
* (i.e. java.lang (See no trailing '.'). When the
* closure compiler sees a class whose package name
* matches this name, it does not try to compute the
* closure of that class any more. It merely adds that
* class name to the closure. So the final closure will
* contain that class name, but not its dependencies.
*/
public void addExcludedPackage(String pkgName) {
imp.addExcludedPackage(pkgName);
}
/**
* @param pattern the pattern for the names of classes to be excluded from
* closure computation. It is in the external format (i.e.
* org.apache.). When the closure compiler sees a class whose
* name begins with this pattern, it does not try to compute
* the closure of that class any more. It merely adds that
* class name to the closure. So the final closure will
* contain that class name, but not its dependencies. Among
* all the excluded list, it is given the lowest priority in
* search order.
*/
public void addExcludedPattern(String pattern) {
imp.addExcludedPattern(pattern);
}
//See corresponding method of ClosureCompiler for javadocs
public boolean buildClosure(String className) {
logger.entering(myClassName, "buildClosure", className); // NOI18N
return imp.buildClosure(className);
}
/**
* @param jar whose classes it will try to build closure of. This is a
* convenience method which iterates over all the entries in a
* jar file and computes their closure.
*/
public boolean buildClosure(java.util.jar.JarFile jar) throws IOException {
return imp.buildClosure(jar);
}
//See corresponding method of ClosureCompiler for javadocs
public Collection getClosure() {
return imp.getClosure();
}
//See corresponding method of ClosureCompiler for javadocs
public Map getFailed() {
return imp.getFailed();
}
/**
* Reset the closure for next closure computation.
* Clear the internal cache. It includes the result it has collected since
* last reset(). But it does not clear the excludedd list. If you want to
* reset the excluded list, create a new ClosureCompiler.
*/
public void reset() {
imp.reset();
}
public Collection getNativeMethods() {
return imp.getNativeMethods();
}
public String toString() {
return imp.toString();
}
public static void main(String[] args) {
if (args.length < 2) {
System.out.println(
"Usage : java " + com.sun.enterprise.tools.verifier.apiscan.classfile.ClosureCompilerImpl.class.getName() + // NOI18N
" "); // NOI18N
System.out.println("Example: to find the closure of " + // NOI18N
"mypkg.MySessionBean which is packaged in myejb.jar run\n" + // NOI18N
" java " + com.sun.enterprise.tools.verifier.apiscan.classfile.ClosureCompilerImpl.class.getName() + // NOI18N
" path_to_j2ee.jar"+File.pathSeparator+"path_to_myejb.jar"+ // NOI18N
" mypkg.MySessionBean"); // NOI18N
System.exit(1);
}
String cp=args[0];
System.out.println("Using classpath " + cp); // NOI18N
ClassFileLoader cfl = ClassFileLoaderFactory.newInstance(
new Object[]{cp});
ClosureCompilerImpl closure = new ClosureCompilerImpl(cfl);
closure.addExcludedPattern("java."); // NOI18N
for (int i = 1; i < args.length; i++) {
String clsName = args[i];
System.out.println("Building closure for " + clsName); // NOI18N
closure.reset();
closure.buildClosure(clsName);
System.out.println("The closure is [" + closure+"\n]"); // NOI18N
}
}
}