/*
This file is part of JOP, the Java Optimized Processor
see <http://www.jopdesign.com/>
Copyright (C) 2008, Martin Schoeberl (martin@jopdesign.com)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
*
*/
package com.jopdesign.build;
import org.apache.bcel.classfile.DescendingVisitor;
import org.apache.bcel.classfile.EmptyVisitor;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.Method;
import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* The new version of ClassInfo
* @author Martin Schoeberl
* @deprecated
*/
public class OldClassInfo implements Serializable {
/**
* Is invoked on cli map creation for additional information setting.
*
* @author Martin Schoeberl
*/
protected class CliVisitor extends EmptyVisitor implements Serializable {
private static final long serialVersionUID = 1L;
protected Map<String, OldClassInfo> map;
protected OldClassInfo cli;
public CliVisitor(Map<String, OldClassInfo> map) {
this.map = map;
}
public void visitJavaClass(JavaClass clazz) {
cli = map.get(clazz.getClassName());
cli.superClass = map.get(clazz.getSuperclassName());
if (clazz.getClassName().equals("java.lang.Object")) {
// Object has no super class
cli.superClass = null;
} else {
// add this ClassInfo as a known sub class to the super class
cli.superClass.subClasses.add(map.get(clazz.getClassName()));
}
}
public void visitMethod(Method method) {
OldClassInfo cli = (OldClassInfo) this.cli;
String methodId = method.getName()+method.getSignature();
if(!cli.methods.containsKey(methodId)) {
OldMethodInfo mi1 = cli.newMethodInfo(methodId);
cli.methods.put(methodId, mi1);
cli.list.add(mi1);
}
OldMethodInfo mi = cli.getMethodInfo(methodId);
mi.setMethod(method);
/* NOTE: don't set MethodGen here. You have to explicitly ask for it later,
* as changing bytecode will invalidate the MethodGen
*/
}
}
private static final long serialVersionUID = 1L;
/**
* The BCEL class representation.
*/
public JavaClass clazz;
/**
* Reference to the super class.
*/
public OldClassInfo superClass;
/**
* Set of sub classes.
*/
private Set<OldClassInfo> subClasses = new HashSet<OldClassInfo>();
/**
* Back link to the application info
*/
public OldAppInfo appInfo;
/**
* Map of method signatures to a MethodInfo.
*/
protected Map<String, OldMethodInfo> methods = new HashMap<String, OldMethodInfo>();
/**
* Methods in a list ordered in the visit order.
*/
protected List<OldMethodInfo> list = new LinkedList<OldMethodInfo>();
protected OldClassInfo(JavaClass jc, OldAppInfo ai) {
clazz = jc;
appInfo = ai;
}
/**
* A dummy instance for the dispatch of newClassInfo() that
* creates the real ClassInfo sub type
*/
public static OldClassInfo getTemplate() {
return new OldClassInfo(null, null);
}
/**
* Create ClassInfos and the map from class names to ClassInfo
* @param jc
* @return
*/
Map<String, ? extends OldClassInfo> genClassInfoMap(JavaClass jc[], OldAppInfo ai) {
Map<String, OldClassInfo> map = new HashMap<String, OldClassInfo>();
for (int i=0; i<jc.length; ++i) {
OldClassInfo cli = newClassInfo(jc[i], ai);
map.put(cli.clazz.getClassName(), cli);
}
// second iteration over all class infos for additional information setting
CliVisitor v = newCliVisitor(map);
Iterator<? extends OldClassInfo> it = map.values().iterator();
while (it.hasNext()) {
JavaClass clz = it.next().clazz;
new DescendingVisitor(clz, v).visit();
}
return map;
}
/**
* A funny version of a factory method to create ClassInfo
* types. Has to be overwritten by each sub-type.
* Wolfgang and Martin in SF, Saint Mary's Square
*/
public OldClassInfo newClassInfo(JavaClass jc,OldAppInfo ai) {
return new OldClassInfo(jc, ai);
}
/**
* Another funny factory method.
* @param map
* @return
*/
public CliVisitor newCliVisitor(Map<String, OldClassInfo> map) {
return new CliVisitor(map);
}
/**
* And another funny factory.
* @param mid
* @return
*/
public OldMethodInfo newMethodInfo(String mid) {
return new OldMethodInfo(this, mid);
}
public String toString() {
return clazz.getClassName();
}
public OldMethodInfo getMethodInfo(String amth) {
return methods.get(amth);
}
public Map<String, OldMethodInfo> getMethodInfoMap() {
return methods;
}
/**
* Return the methods as list in the order they have been visited.
* @return
*/
public List<OldMethodInfo> getMethods() {
return list;
}
/**
* Write the BCEL clazz to a class file. 'Stolen' from Stefan's libgraph.
* @param filename
* @throws IOException
*/
public void writeClassFile(String filename) throws IOException {
File file = new File(filename);
String parent = file.getParent();
if(parent != null) {
File dir = new File(parent);
dir.mkdirs();
}
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file));
// TODO: what happens if we have changed the class (gen)?
// updateClass();
clazz.dump(new DataOutputStream(out));
}
}