/*
 * 作成日: 2005/10/31
 */
package asandatabasebrowser.util;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * java.net.URLClassLoaderを使いましょう。
 * 一度例外が発生してしまうと、そのスレッドは破棄され、新しいスレッドが立ち上がる。
 * そのとき、クラスローダはコレではないので、正しいクラスを見つけることができない。
 */
public class JarClassLoader extends ClassLoader {
	 
	ArrayList jarnames;
	/**
	 * @param paths	個々のパスには末尾にセパレータをつけないこと。
	 */
	public JarClassLoader() {
		this.jarnames = new ArrayList();
	}
	public void setJarFilenames(ArrayList jarnames) {
		this.jarnames = jarnames;
	}
	
	public Class findClass(String name) {
		byte[] b = loadClassData(name);
		if (b == null) return null;
		return defineClass(name, b, 0, b.length);
	}

	protected URL findResource(String name) {
		//System.out.println("findResource() "+name);
		for (int i=0; i<jarnames.size(); i++) {
			String jarname = (String) jarnames.get(i);
			try {
				JarFile jarfile = new JarFile(jarname);
				JarEntry entry = jarfile.getJarEntry(name);
				// 見つかった
				if (entry != null) {
					try {
						return new URL("jar:file:"+jarnames.get(i)+"!/"+name);
					} catch (MalformedURLException e) {
						//e.printStackTrace();
					}
				}
			} catch (IOException e) {
				//e.printStackTrace();
			}
		}
		System.out.println("見つからなかった(;_;):findResource("+name+")");
		return null;
	}

	/**
	 * 指定されたパスを使って、サーバのクラスを取得する.
	 */
	private byte[] loadClassData(String name) {
		//System.out.println(name);
		for (int i=0; i<jarnames.size(); i++) {
			String jarname = (String) jarnames.get(i);
			byte[] bytes = loadClassData1(name, jarname);
			if (bytes != null) return bytes;
		}
		System.out.println("見つからなかった(;_;):loadClassData("+name+")");
		return null;	// 見つからなかった(;_;)
	}
	private byte[] loadClassData1(String name, String jarname) {
		String fname = name.replace('.', '\\') + ".class";
		String fname2 = name.replace('.', '/') + ".class";
		try {
			JarFile jarfile = new JarFile(jarname);
			JarEntry entry = jarfile.getJarEntry(fname);
			if (entry == null) {
				entry = jarfile.getJarEntry(fname2);
			}
			if (entry == null) return null;		// 見つからなかった(;_;)
			BufferedInputStream in = new BufferedInputStream(jarfile.getInputStream(entry));
			byte[] bytes = new byte[(int) entry.getSize()];
			int size = in.read(bytes);
			assert size == entry.getSize();
			in.close();
			return bytes;
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;	// 見つからなかった(;_;)
	}
}
