|
Glassfish example source code file (ASMClosureCompilerImpl.java)
This example Glassfish source code file (ASMClosureCompilerImpl.java) is included in the DevDaily.com
"Java Source Code
Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.
The Glassfish ASMClosureCompilerImpl.java source code
/*
* 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.
*/
/*
* ASMClosureCompilerImpl.java
*
* Created on August 13, 2004, 3:34 PM
*/
package com.sun.enterprise.tools.verifier.apiscan.classfile;
import java.io.IOException;
import java.util.*;
import java.util.logging.Level;
/**
* An implementation of {@link ClosureCompilerImplBase} based on
* ASM.
*
* It is not a public class because I expect users to use this class via
* the bridge setup from {@link ClosureCompilerImpl}.
* It extends the common implementation from ClosureCompilerImplBase.
* @author Sanjeeb.Sahoo@Sun.COM
*/
class ASMClosureCompilerImpl extends ClosureCompilerImplBase {
private Collection<MethodRef> methodReferences = new HashSet();
private HashSet<MethodRef> visitedMethods = new HashSet();
private Stack<MethodRef> callStack = new Stack();
// holds result of current buildClosure() method
private boolean result;
private HashSet<String> closure = new HashSet();
//map of refencing path to list of not found classes.
private Map<String, List failed = new HashMap>();
private static final String myClassName = "ASMClosureCompilerImpl"; // NOI18N
/**
* @param loader the ClassFileLoader that is used to load the referenced
* classes.
*/
public ASMClosureCompilerImpl(ClassFileLoader loader) {
super(loader);
}
private void resetResult() {
logger.entering("ASMClosureCompilerImpl", "resetResult", // NOI18N
new Object[]{});
result = true;
}
private void setResult(boolean newresult){
result = result && newresult;
}
private boolean getResult() {
return result;
}
/**
* {@inheritDoc}
*/
public boolean buildClosure(String className) {
logger.entering(myClassName, "buildClosure", className); // NOI18N
resetResult(); // at the entry of this public method, we reset result.
if (needToBuildClosure(className)) {
visitedClasses.add(className); // yes, we add before visting
ClassFile cf = load(className);
if(cf==null){
return false;
}
// top level methods whose closure needs to be calculated.
// TODO: We must get precise list of methods.
Collection<? extends Method> methods = cf.getMethods();
for(Method next:methods){
methodReferences.add(next.getSelfReference());
buildClosure(next);
}
}
return getResult();
}
private void buildClosure(Method m) {
MethodRef methodReference = m.getSelfReference();
logger.entering("ASMClosureCompilerImpl", "buildClosure", // NOI18N
new Object[]{methodReference});
callStack.push(methodReference);
if (needToBuildClosure(methodReference)) {
visitedMethods.add(methodReference);
Collection<MethodRef> methodRefs = m.getReferencedMethods();
methodReferences.addAll(methodRefs);
for(MethodRef nextMethodRef : methodRefs) {
if (!needToBuildClosure(nextMethodRef)) continue;
ClassFile cf = load(Util.convertToExternalClassName
(nextMethodRef.getOwningClassName()));
if (cf == null) {
continue; // no need to call handleFailure() as it is done by this.load()
}
Method nextMethod = cf.getMethod(nextMethodRef);
if(nextMethod==null){
handleFailure(nextMethodRef);
continue;
}
buildClosure(nextMethod);//recurssive call
} // for
// now go thru' all the classes that will be loaded when this
// method is called.
for(String className : m.getReferencedClasses()){
String externalClassName = Util.convertToExternalClassName(className);
if(!needToBuildClosure(externalClassName)) continue;
load(externalClassName);
}
}
callStack.pop();
}
/**
* load class with given name. It also recurssively loads all classes in the
* super class chain and interfaces implemented by this class and
* its super classes, until it reaches a class which is found in the
* excluded list. It also builds closure of each of the class's clinit method.
*
* @param className name of class in external format.
* @return ClassFile representing this class name,
* It returns null if class has been already loaded or need not be loaded
* because it is an excluded class or could not be loaded. If class could
* could not be loaded, it calls appropriate handleFailure().
* @see #needToLoad(String)
*/
protected ClassFile load(String className) {
logger.entering("ASMClosureCompilerImpl", "load", // NOI18N
new Object[]{className});
ClassFile cf = null;
try{
cf = loader.load(className);
}catch(IOException e){
handleFailure(className);
}
if((cf!=null) && needToLoad(className)) {
closure.add(className); // yes we add before actually loading.
MethodRef clinitMethodRef =
new MethodRef(Util.convertToInternalClassName(className),
MethodRef.CLINIT_NAME,
MethodRef.CLINIT_DESC);
Method clinitMethod = cf.getMethod(clinitMethodRef);
try{
// See we push clinitMethodRef here so that we can display
// useful error to user even during class loading.
callStack.push(clinitMethodRef);
String superClassName = cf.getNameOfSuperClass();
if(superClassName!=null && needToBuildClosure(superClassName)) { // super class of java.lang.Object is null
load(superClassName); //recurssive call
}
for(String interfaceClassName : cf.getNamesOfInterfaces()){
if(needToBuildClosure(interfaceClassName)) {
load(interfaceClassName); // recurssive call
}
}
}finally{
// pop callStack before buildClosure is called for clinit
callStack.pop();
}
if(clinitMethod!=null) {
methodReferences.add(clinitMethodRef);
buildClosure(clinitMethod); // recurssive call
}
}
logger.exiting("ASMClosureCompilerImpl", "load", cf==null?"null":cf.getName()); // NOI18N
return cf;
}
private void handleFailure(MethodRef mr){
logger.logp(Level.WARNING, "ASMClosureCompilerImpl", "handleFailure",
getClass().getName() + ".exception1", new Object[]{mr.toString()});
// setResult(false);
// TODO: We should look for base class methods
}
/**
* @param referencedClass is the name of the class in external format.
*/
private void handleFailure(String referencedClass) {
logger.entering("ASMClosureCompilerImpl", "handleFailure", // NOI18N
new Object[]{referencedClass});
setResult(false);
String referencingPath = "";
try {
StringBuilder referencingPathBuffer = new StringBuilder();
for (MethodRef m : callStack) {
if (referencingPathBuffer.length() != 0)
referencingPathBuffer.append("->"); // NOI18N
referencingPathBuffer.append(m);
}
referencingPath = referencingPathBuffer.toString();
} catch (EmptyStackException e) {
}
List<String> failedList = failed.get(referencingPath);
if (failedList == null) {
failedList = new ArrayList<String>();
failed.put(referencingPath, failedList);
}
failedList.add(referencedClass);
}
/**
* {@inheritDoc}
*/
public Collection getClosure() {
return Collections.unmodifiableCollection(methodReferences);
}
/**
* {@inheritDoc}
*/
public Map getFailed() {
return Collections.unmodifiableMap(failed);
}
/**
* 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() {
methodReferences.clear();
visitedClasses.clear();
failed.clear();
closure.clear();
}
/**
* @param className name of class in external format.
* @return
*/
protected boolean needToLoad(String className) {
return !closure.contains(className);
}
protected boolean needToBuildClosure(MethodRef methodRef) {
boolean result = true;
final String owningClassName = methodRef.getOwningClassName();
if (visitedMethods.contains(methodRef))
result = false;
else if (excludedClasses.contains(owningClassName)) {
result = false;
} else if (excludedPackages.contains(getPackageName(owningClassName))) {
result = false;
} else {
for (Iterator i = excludedPatterns.iterator(); i.hasNext();) {
String pattern = (String) i.next();
if (owningClassName.startsWith(pattern)) {
result = false;
break;
}
}
}
logger.logp(Level.FINEST, myClassName, "needToBuildClosure", // NOI18N
methodRef + " " + result); // NOI18N
return result;
}
// used for pretty printing
public String toString() {
StringBuilder sb=new StringBuilder();
if(logger.isLoggable(Level.FINER)){
sb.append("\n<Closure>"); // NOI18N
sb.append("\n\t<ExcludedClasses>"); // NOI18N
for(Iterator i=excludedClasses.iterator(); i.hasNext();) {
sb.append("\n\t\t"); // NOI18N
sb.append((String)i.next());
}
sb.append("\n\t</ExcludedClasses>"); // NOI18N
sb.append("\n\t<ExcludedPackages>"); // NOI18N
for(Iterator i=excludedPackages.iterator(); i.hasNext();){
sb.append("\n\t\t"); // NOI18N
sb.append((String)i.next());
}
sb.append("\n\t</ExcludedPackages>"); // NOI18N
sb.append("\n\t<ExcludedPatterns>"); // NOI18N
for(Iterator i=excludedPatterns.iterator(); i.hasNext();){
sb.append("\n\t\t"); // NOI18N
sb.append((String)i.next());
}
sb.append("\n\t</ExcludedPatterns>"); // NOI18N
sb.append("\n\t<Methods>"); // NOI18N
for(MethodRef m : methodReferences){
sb.append("\n\t\t"); // NOI18N
sb.append(m);
}
sb.append("\n\t</Methods>"); // NOI18N
sb.append("\n\t<Closure>"); // NOI18N
for(String c : closure){
sb.append("\n\t\t"); // NOI18N
sb.append(c);
}
sb.append("\n\t</Closure>"); // NOI18N
}
sb.append("\n\t<Failed>"); // NOI18N
for(Iterator i=failed.entrySet().iterator(); i.hasNext();) {
Map.Entry referencingPathToFailedList=(Map.Entry)i.next();
sb.append("\n\t\t"); // NOI18N
sb.append("<ReferencingPath>"); // NOI18N
sb.append("\n\t\t\t"); // NOI18N
sb.append(referencingPathToFailedList.getKey());
sb.append("\n\t\t"); // NOI18N
sb.append("</ReferencingPath>"); // NOI18N
sb.append("\n\t\t"); // NOI18N
sb.append("<Classes>"); // NOI18N
for(Iterator iii=((List)referencingPathToFailedList.getValue()).iterator(); iii.hasNext();){
sb.append("\n\t\t\t"); // NOI18N
sb.append((String)iii.next());
}
sb.append("\n\t\t"); // NOI18N
sb.append("</Classes>"); // NOI18N
}
sb.append("\n\t</Failed>"); // NOI18N
if(logger.isLoggable(Level.FINER)){
sb.append("\n</Closure>"); // NOI18N
}
return sb.toString();
}
}
Other Glassfish examples (source code examples)
Here is a short list of links related to this Glassfish ASMClosureCompilerImpl.java source code file:
|