220 lines
7.3 KiB
Java
220 lines
7.3 KiB
Java
/* Copyright (C) 2004 Vladimir Roubtsov. All rights reserved.
|
|
*
|
|
* This program and the accompanying materials are made available under
|
|
* the terms of the Common Public License v1.0 which accompanies this distribution,
|
|
* and is available at http://www.eclipse.org/legal/cpl-v10.html
|
|
*
|
|
* $Id: ClassDep.java,v 1.1.2.2 2004/07/09 01:42:04 vlad_r Exp $
|
|
*/
|
|
package com.vladium.tools;
|
|
|
|
import java.io.File;
|
|
import java.io.FileOutputStream;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.net.URL;
|
|
import java.net.URLClassLoader;
|
|
import java.util.ArrayList;
|
|
import java.util.HashSet;
|
|
import java.util.Iterator;
|
|
import java.util.LinkedList;
|
|
import java.util.List;
|
|
import java.util.Properties;
|
|
import java.util.Set;
|
|
import java.util.StringTokenizer;
|
|
|
|
import com.vladium.jcd.cls.ClassDef;
|
|
import com.vladium.jcd.cls.IConstantCollection;
|
|
import com.vladium.jcd.cls.constant.CONSTANT_Class_info;
|
|
import com.vladium.jcd.cls.constant.CONSTANT_info;
|
|
import com.vladium.jcd.parser.ClassDefParser;
|
|
import com.vladium.util.ByteArrayOStream;
|
|
import com.vladium.util.Descriptors;
|
|
|
|
// ----------------------------------------------------------------------------
|
|
/**
|
|
* TODO: doc
|
|
*
|
|
* @author Vlad Roubtsov, (C) 2004
|
|
*/
|
|
public class ClassDep
|
|
{
|
|
// public: ................................................................
|
|
|
|
public static void main (final String [] args)
|
|
throws Exception
|
|
{
|
|
if (args.length < 2)
|
|
throw new IllegalArgumentException ("usage: classpath output_file rootset_classname_1 [rootset_classname_2 ...]");
|
|
|
|
final String _classPath = args [0];
|
|
final URL [] classPath;
|
|
{
|
|
final StringTokenizer tokenizer = new StringTokenizer (_classPath, File.pathSeparator);
|
|
classPath = new URL [tokenizer.countTokens ()];
|
|
|
|
for (int i = 0; tokenizer.hasMoreTokens (); ++ i)
|
|
{
|
|
classPath [i] = new File (tokenizer.nextToken ()).toURL ();
|
|
}
|
|
}
|
|
|
|
final File outFile = new File (args [1]);
|
|
|
|
final int offset = 2;
|
|
final String [] rootSet = args.length > offset
|
|
? new String [args.length - offset]
|
|
: new String [0];
|
|
{
|
|
for (int a = 0; a < rootSet.length; ++ a)
|
|
{
|
|
rootSet [a] = args [a + offset];
|
|
}
|
|
}
|
|
|
|
final ClassDep _this = new ClassDep (rootSet, classPath);
|
|
final String [] deps = _this.getDependencies (true);
|
|
|
|
final StringBuffer s = new StringBuffer ();
|
|
for (int d = deps.length - 1; d >= 0; -- d) // reverse topological order
|
|
{
|
|
s.append (deps [d]);
|
|
if (d > 0) s.append (',');
|
|
}
|
|
|
|
final File parent = outFile.getParentFile ();
|
|
if (parent != null) parent.mkdirs ();
|
|
|
|
final FileOutputStream out = new FileOutputStream (outFile);
|
|
|
|
final Properties result = new Properties ();
|
|
result.setProperty ("closure", s.toString ());
|
|
|
|
result.store (out, "this file is auto-generated, do not edit");
|
|
|
|
out.close ();
|
|
}
|
|
|
|
|
|
public ClassDep (final String [] rootSet, final URL [] classPath)
|
|
{
|
|
if (rootSet == null)
|
|
throw new IllegalArgumentException ("null input: rootSet");
|
|
|
|
if (classPath == null)
|
|
throw new IllegalArgumentException ("null input: classPath");
|
|
|
|
m_rootSet = rootSet;
|
|
m_classPath = classPath;
|
|
}
|
|
|
|
public String [] getDependencies (final boolean includeRootSet)
|
|
throws IOException
|
|
{
|
|
final Set /* class Java name:String */ _result = new HashSet ();
|
|
final ClassLoader loader = new URLClassLoader (m_classPath, null);
|
|
|
|
if (includeRootSet)
|
|
{
|
|
for (int i = 0; i < m_rootSet.length; ++ i)
|
|
{
|
|
_result.add (m_rootSet [i]);
|
|
}
|
|
}
|
|
|
|
final LinkedList /* class VM name:String */ queue = new LinkedList ();
|
|
for (int i = 0; i < m_rootSet.length; ++ i)
|
|
{
|
|
queue.add (Descriptors.javaNameToVMName (m_rootSet [i]));
|
|
}
|
|
|
|
final ByteArrayOStream baos = new ByteArrayOStream (8 * 1024);
|
|
final byte [] readbuf = new byte [8 * 1024];
|
|
|
|
while (! queue.isEmpty ())
|
|
{
|
|
final String classVMName = (String) queue.removeFirst ();
|
|
|
|
// keep at most one file descriptor open:
|
|
|
|
InputStream in = null;
|
|
try
|
|
{
|
|
// NOTE: getResources() not used
|
|
in = loader.getResourceAsStream (classVMName + ".class");
|
|
|
|
if (in == null)
|
|
{
|
|
throw new IllegalArgumentException ("class [" + Descriptors.vmNameToJavaName (classVMName) + "] not found in the input classpath");
|
|
}
|
|
else
|
|
{
|
|
baos.reset ();
|
|
for (int read; (read = in.read (readbuf)) >= 0; baos.write (readbuf, 0, read));
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
if (in != null) try { in.close (); } catch (IOException ignore) { ignore.printStackTrace (); }
|
|
}
|
|
in = null;
|
|
|
|
final ClassDef cls = ClassDefParser.parseClass (baos.getByteArray (), baos.size ());
|
|
final List /* class VM name:String */ clsDeps = getCONSTANT_Class_info (cls);
|
|
|
|
for (Iterator i = clsDeps.iterator (); i.hasNext (); )
|
|
{
|
|
final String classDepVMName = (String) i.next ();
|
|
|
|
if (classDepVMName.startsWith ("com/vladium/")) // TODO: generic filtering
|
|
{
|
|
if (_result.add (Descriptors.vmNameToJavaName (classDepVMName)))
|
|
{
|
|
queue.addLast (classDepVMName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
final String [] result = new String [_result.size ()];
|
|
_result.toArray (result);
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* @return array of class VM names [may contain duplicates]
|
|
*/
|
|
public static List getCONSTANT_Class_info (final ClassDef cls)
|
|
{
|
|
if (cls == null)
|
|
throw new IllegalArgumentException ("null input: cls");
|
|
|
|
final IConstantCollection constants = cls.getConstants ();
|
|
final IConstantCollection.IConstantIterator i = constants.iterator ();
|
|
|
|
final List result = new ArrayList ();
|
|
|
|
for (CONSTANT_info entry; (entry = i.nextConstant ()) != null; )
|
|
{
|
|
if (entry instanceof CONSTANT_Class_info)
|
|
{
|
|
result.add (((CONSTANT_Class_info) entry).getName (cls));
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// protected: .............................................................
|
|
|
|
// package: ...............................................................
|
|
|
|
// private: ...............................................................
|
|
|
|
|
|
private final String [] m_rootSet;
|
|
private final URL [] m_classPath;
|
|
|
|
} // end of class
|
|
// ---------------------------------------------------------------------------- |