/** * Copyright 2008 - 2012 * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. * * @project loon * @author cping * @email:javachenpeng@yahoo.com * @version 0.3.3 */ package loon; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.net.URLConnection; import java.net.URLDecoder; import java.net.URLStreamHandler; import java.net.URLStreamHandlerFactory; import java.util.ArrayList; import java.util.Enumeration; import java.util.jar.Attributes; import java.util.jar.Manifest; /** * 多jar打包加载用类(修改自org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader) * * Manifest-Version: 1.0 * Rsrc-Class-Path: ./ LGame-JavaSE-0.3.3.jar lwjgl.jar * Class-Path: . * Rsrc-Main-Class: com.mianfilename * Main-Class: loon.JarInternal */ public class JarInternal { public static class RsrcURLStreamHandlerFactory implements URLStreamHandlerFactory { private ClassLoader classLoader; private URLStreamHandlerFactory chainFac; public RsrcURLStreamHandlerFactory(ClassLoader cl) { this.classLoader = cl; } public URLStreamHandler createURLStreamHandler(String protocol) { if ("rsrc".equals(protocol)) { return new RsrcURLStreamHandler(this.classLoader); } if (this.chainFac != null) { return this.chainFac.createURLStreamHandler(protocol); } return null; } public void setURLStreamHandlerFactory(URLStreamHandlerFactory fac) { this.chainFac = fac; } } public static class RsrcURLConnection extends URLConnection { private ClassLoader classLoader; public RsrcURLConnection(URL url, ClassLoader classLoader) { super(url); this.classLoader = classLoader; } public void connect() throws IOException { } public InputStream getInputStream() throws IOException { String file = URLDecoder.decode(this.url.getFile(), "UTF-8"); InputStream result = this.classLoader.getResourceAsStream(file); if (result == null) { throw new MalformedURLException( "Could not open InputStream for URL '" + this.url + "'"); } return result; } } public static class RsrcURLStreamHandler extends URLStreamHandler { private ClassLoader classLoader; public RsrcURLStreamHandler(ClassLoader c) { this.classLoader = c; } protected URLConnection openConnection(URL u) throws IOException { return new RsrcURLConnection(u, this.classLoader); } protected void parseURL(URL url, String spec, int start, int limit) { String file = null; if (spec.startsWith(INTERNAL_URL_PROTOCOL_WITH_COLON)) { file = spec.substring(5); } else { if (url.getFile().equals(CURRENT_DIR)) { file = spec; } else { if (url.getFile().endsWith(PATH_SEPARATOR)) { file = url.getFile() + spec; } else { file = spec; } } } setURL(url,INTERNAL_URL_PROTOCOL, "", -1, null, null, file, null, null); } } static final String REDIRECTED_CLASS_PATH_MANIFEST_NAME = "Rsrc-Class-Path"; static final String REDIRECTED_MAIN_CLASS_MANIFEST_NAME = "Rsrc-Main-Class"; static final String DEFAULT_REDIRECTED_CLASSPATH = ""; static final String MAIN_METHOD_NAME = "main"; static final String JAR_INTERNAL_URL_PROTOCOL_WITH_COLON = "jar:rsrc:"; static final String JAR_INTERNAL_SEPARATOR = "!/"; static final String INTERNAL_URL_PROTOCOL_WITH_COLON = "rsrc:"; static final String INTERNAL_URL_PROTOCOL = "rsrc"; static final String PATH_SEPARATOR = "/"; static final String CURRENT_DIR = "./"; private static ManifestInfo getManifestInfo() throws IOException { Enumeration<URL> resEnum = Thread.currentThread() .getContextClassLoader().getResources("META-INF/MANIFEST.MF"); while (resEnum.hasMoreElements()) { try { URL url = resEnum.nextElement(); InputStream is = url.openStream(); if (is != null) { ManifestInfo result = new ManifestInfo(null); Manifest manifest = new Manifest(is); Attributes mainAttribs = manifest.getMainAttributes(); result.rsrcMainClass = mainAttribs .getValue(REDIRECTED_MAIN_CLASS_MANIFEST_NAME); String rsrcCP = mainAttribs.getValue(REDIRECTED_CLASS_PATH_MANIFEST_NAME); if (rsrcCP == null) { rsrcCP = ""; } result.rsrcClassPath = splitSpaces(rsrcCP); if ((result.rsrcMainClass != null) && (!result.rsrcMainClass.trim().equals(""))) { return result; } } } catch (Exception ex) { ex.printStackTrace(); } } System.err .println("Missing attributes for JarRsrcLoader in Manifest (Rsrc-Main-Class, Rsrc-Class-Path)"); return null; } private static String[] splitSpaces(String line) { if (line == null) { return null; } ArrayList<String> result = new ArrayList<String>(); int firstPos = 0; while (firstPos < line.length()) { int lastPos = line.indexOf(' ', firstPos); if (lastPos == -1) { lastPos = line.length(); } if (lastPos > firstPos) { result.add(line.substring(firstPos, lastPos)); } firstPos = lastPos + 1; } return result.toArray(new String[result.size()]); } private static class ManifestInfo { String rsrcMainClass; String[] rsrcClassPath; private ManifestInfo() { } ManifestInfo(ManifestInfo paramManifestInfo) { this(); } } public static void main(String[] args) throws ClassNotFoundException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException, IOException { ManifestInfo mi = getManifestInfo(); ClassLoader cl = Thread.currentThread().getContextClassLoader(); URL.setURLStreamHandlerFactory(new RsrcURLStreamHandlerFactory(cl)); URL[] rsrcUrls = new URL[mi.rsrcClassPath.length]; for (int i = 0; i < mi.rsrcClassPath.length; i++) { String rsrcPath = mi.rsrcClassPath[i]; if (rsrcPath.endsWith(PATH_SEPARATOR)) { rsrcUrls[i] = new URL(INTERNAL_URL_PROTOCOL_WITH_COLON + rsrcPath); } else { rsrcUrls[i] = new URL(JAR_INTERNAL_URL_PROTOCOL_WITH_COLON + rsrcPath + JAR_INTERNAL_SEPARATOR); } } ClassLoader jceClassLoader = new URLClassLoader(rsrcUrls, null); Thread.currentThread().setContextClassLoader(jceClassLoader); Class<?> c = Class.forName(mi.rsrcMainClass, true, jceClassLoader); Method main = c.getMethod(MAIN_METHOD_NAME, new Class[] { args.getClass() }); main.invoke(null, new Object[] { args }); } }