Java tutorial
/* * Copyright 2011-2016 ZXC.com All right reserved. This software is the confidential and proprietary information of * ZXC.com ("Confidential Information"). You shall not disclose such Confidential Information and shall use it only in * accordance with the terms of the license agreement you entered into with ZXC.com. */ package com.ms.commons.test.classloader; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedWriter; import java.io.File; import java.io.FileFilter; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.Writer; import java.lang.reflect.Field; import java.net.URL; import java.net.URLClassLoader; import java.net.URLStreamHandlerFactory; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.regex.Pattern; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.jdom.Document; import org.jdom.Element; import org.jdom.input.SAXBuilder; import org.jdom.output.XMLOutputter; import org.jdom.xpath.XPath; import sun.misc.Launcher; import sun.misc.Resource; import sun.misc.URLClassPath; import com.ms.commons.test.classloader.manifest.CopiedJDK5Manifest; import com.ms.commons.test.classloader.util.AutoConfigItem; import com.ms.commons.test.classloader.util.AutoConfigMap; import com.ms.commons.test.classloader.util.AutoConfigUtil; import com.ms.commons.test.classloader.util.ClassDependcyUtil; import com.ms.commons.test.classloader.util.ClassPathAccessor; import com.ms.commons.test.common.CollectionUtil; import com.ms.commons.test.common.ExceptionUtil; import com.ms.commons.test.common.FileUtil; import com.ms.commons.test.common.StringUtil; import com.ms.commons.test.common.tool.OutputWriter; import com.ms.commons.test.constants.IntlTestGlobalConstants; import com.ms.commons.test.runtime.RuntimeUtil; import com.ms.commons.test.runtime.constant.RuntimeEnvironment; /** * intl-test URLClassPath * * @author zxc Apr 13, 2013 11:06:28 PM */ public class IntlTestURLClassPath extends URLClassPath { private static final String ISOLATED_CLASS_LOADER = "org.apache.maven.surefire.booter.IsolatedClassLoader"; private static final String TESTCASE_JAR_SIGNATURE = ".intl_test_signature"; private static final String TESTCASE_JAR_TEMP_DIR = IntlTestGlobalConstants.TESTCASE_TEMP_DIR + File.separator + "expand_jars"; private static final String TESTCASE_SPRING_TEMP_DIR = IntlTestGlobalConstants.TESTCASE_TEMP_DIR + File.separator + "spring_xml"; static { new File(TESTCASE_JAR_TEMP_DIR).mkdirs(); FileUtil.clearAndMakeDirs(TESTCASE_SPRING_TEMP_DIR); } private static final String TESTCASE_TEMP_LDRES_DIR = IntlTestGlobalConstants.TESTCASE_TEMP_DIR + File.separator + "loaded_resources" + File.separator + "loadedResources.txt"; // parent class constructors public IntlTestURLClassPath(URL[] paramArrayOfURL, URLStreamHandlerFactory paramURLStreamHandlerFactory) { super(paramArrayOfURL, paramURLStreamHandlerFactory); throw new RuntimeException("Never called!"); } // parent class constructors public IntlTestURLClassPath(URL[] paramArrayOfURL) { super(paramArrayOfURL); throw new RuntimeException("Never called!"); } public IntlTestURLClassPath(URLClassPath urlClassPath) { super(getParamArrayOfURL(urlClassPath), getURLStreamHandlerFactory()); } public static boolean isIntlTestURLClassPathInited = false; synchronized public static void initIntlTestURLClassLoader() { if (!isIntlTestURLClassPathInited) { try { System.err.println(">>>>>> Begin 'IntlTestURLClassPath'. >>>>>>>>>>>>>>>>>>"); long BEGIN = System.currentTimeMillis(); System.err.println("Current classloader: " + IntlTestURLClassPath.class.getClassLoader()); { URLClassLoader loader = (URLClassLoader) Launcher.getLauncher().getClassLoader(); Field ucpField = URLClassLoader.class.getDeclaredField("ucp"); ucpField.setAccessible(true); IntlTestURLClassPath itucp = new IntlTestURLClassPath(getLauncherUrlClassPath(loader)); ucpField.set(loader, itucp); } // deal with "org.apache.maven.surefire.booter.IsolatedClassLoader" if (ISOLATED_CLASS_LOADER .equals(IntlTestURLClassPath.class.getClassLoader().getClass().getName())) { System.err.println( " >> Begin 'org.apache.maven.surefire.booter.IsolatedClassLoader'. >>>>>>>>>>>>>>>>>>"); URLClassLoader isoLoader = (URLClassLoader) IntlTestURLClassPath.class.getClassLoader(); Field isoUcpField = URLClassLoader.class.getDeclaredField("ucp"); isoUcpField.setAccessible(true); IntlTestURLClassPath isoItucp = new IntlTestURLClassPath(getLauncherUrlClassPath(isoLoader)); isoUcpField.set(isoLoader, isoItucp); System.err.println( " << Init 'org.apache.maven.surefire.booter.IsolatedClassLoader' successfuled. <<<<<<"); } System.err.println("Do 'IntlTestURLClassPath' cost:" + (System.currentTimeMillis() - BEGIN)); System.err.println("<<<<<< Init 'IntlTestURLClassPath' successfuled. <<<<<<"); isIntlTestURLClassPathInited = true; } catch (Exception e) { throw ExceptionUtil.wrapToRuntimeException(e); } } } private static URLClassPath getLauncherUrlClassPath(URLClassLoader classLoader) { try { Field ucpField = URLClassLoader.class.getDeclaredField("ucp"); ucpField.setAccessible(true); return (URLClassPath) ucpField.get(classLoader); } catch (Exception e) { throw ExceptionUtil.wrapToRuntimeException(e); } } @SuppressWarnings({ "unchecked", "rawtypes" }) private static URL[] getParamArrayOfURL(URLClassPath urlClassPath) { try { Field pathField = urlClassPath.getClass().getDeclaredField("path"); pathField.setAccessible(true); List<URL> path = (List) pathField.get(urlClassPath); path = dealWithMaevnTest(path); path = filterMavenSurefireBooter(path); path = adjustJarIndex(path); getCallCopyAdditationURLPath(); List<URL> translatedPath = new ArrayList<URL>(path.size()); for (URL url : path) { translatedPath.add(translateURL(url)); } System.err.println("Final classpath url(s):" + translatedPath); return translatedPath.toArray(new URL[0]); } catch (Exception e) { throw ExceptionUtil.wrapToRuntimeException(e); } } private static URLStreamHandlerFactory getURLStreamHandlerFactory() { try { Field factoryField = Launcher.class.getDeclaredField("factory"); factoryField.setAccessible(true); return (URLStreamHandlerFactory) factoryField.get(null); } catch (Exception e) { throw ExceptionUtil.wrapToRuntimeException(e); } } private static final OutputWriter OUTPUT_WRITER = OutputWriter.createWriter(TESTCASE_TEMP_LDRES_DIR); @SuppressWarnings("unchecked") public URL findResource(String paramString, boolean paramBoolean) { URL resource = super.findResource(paramString, paramBoolean); URL newResource = null; if (resource != null) { boolean testcaseLazyInit = IntlTestProperties.isAntxFlagOn(IntlTestGlobalConstants.TESTCASE_LAZY_INIT); if (testcaseLazyInit && paramString.contains("spring_") && paramString.endsWith(".xml")) { try { String nResource = TESTCASE_SPRING_TEMP_DIR + "/" + StringUtil.replaceNoWordChars(resource.toString().hashCode() + paramString) + ".xml"; File newF = new File(nResource); if (!newF.exists()) { InputStream is = resource.openStream(); SAXBuilder b = new SAXBuilder(); Document document = b.build(new InputStreamReader(is, "UTF-8")); List<Element> elements = XPath.selectNodes(document, "/beans"); if (elements != null && elements.size() == 1) { elements.get(0).setAttribute("default-lazy-init", "true"); XMLOutputter xmlOutputter = new XMLOutputter(); Writer writer = new BufferedWriter(new FileWriter(newF)); xmlOutputter.output(document, writer); writer.flush(); FileUtil.closeCloseAbleQuitly(writer); } } newResource = newF.toURI().toURL(); } catch (Exception e) { e.printStackTrace(); } } } OUTPUT_WRITER.writeLine("FindResource [" + paramString + "] --> " + resource + ((newResource == null) ? "" : " # " + newResource)); return resource; } public Resource getResource(String paramString) { Resource resource = getResource(paramString, true); return resource; } public Resource getResource(String paramString, boolean paramBoolean) { Resource resource = super.getResource(paramString, paramBoolean); return resource; } @SuppressWarnings({ "unchecked", "rawtypes" }) public Enumeration findResources(String paramString, boolean paramBoolean) { List reses = (List) CollectionUtil.toCollection(ArrayList.class, super.findResources(paramString, paramBoolean)); OUTPUT_WRITER.writeLine("FindResources [" + paramString + "] ==> " + reses); return CollectionUtil.toEnumeration(reses); } @SuppressWarnings("rawtypes") public Enumeration getResources(String paramString) { return getResources(paramString, true); } @SuppressWarnings("rawtypes") public Enumeration getResources(String paramString, boolean paramBoolean) { return super.getResources(paramString, paramBoolean); } // =================================== INTL_TEST SPECIAL =================================== private static List<URL> filterMavenSurefireBooter(List<URL> urlList) { try { if (IntlTestURLClassPath.class.getClassLoader().toString() .contains("sun.misc.Launcher$AppClassLoader")) { if (RuntimeUtil.getRuntime().getEnvironment() == RuntimeEnvironment.Maven) { List<URL> filteredUrlList = new ArrayList<URL>(); for (URL u : urlList) { if (u.toString().contains("surefirebooter")) { System.err.println("URL: " + u.toString() + " has been ingored!"); } else { filteredUrlList.add(u); } } return filteredUrlList; } } } catch (Exception e) { System.err.println("Error in: " + IntlTestURLClassPath.class + "." + "filterMavenSurefireBooter"); e.printStackTrace(); } return urlList; } private static List<URL> dealWithMaevnTest(List<URL> urlList) { List<URL> newUrlList = new ArrayList<URL>(); try { if (IntlTestURLClassPath.class.getClassLoader().toString() .contains("sun.misc.Launcher$AppClassLoader")) { if (RuntimeUtil.getRuntime().getEnvironment() == RuntimeEnvironment.Maven) { CopiedJDK5Manifest mf = findSurefireBooterManifest(); if (mf != null) { String cp = mf.getMainAttributes().getValue("Class-Path"); System.err.println("Maven test class path: " + cp); if (cp != null) { String[] cps = cp.split(" "); for (String c : cps) { try { newUrlList.add(new URL(c.trim())); } catch (Exception e) { System.err.println("Error in: " + IntlTestURLClassPath.class + "." + "dealWithMaevnTest#new URL(" + c + ")"); e.printStackTrace(); } } } } } } } catch (Exception e) { System.err.println("Error in: " + IntlTestURLClassPath.class + "." + "dealWithMaevnTest"); e.printStackTrace(); } newUrlList.addAll(urlList); return newUrlList; } private static List<URL> adjustJarIndex(List<URL> urlList) { int indexOfJ2EE = findJarIndex(urlList, ".*[\\W]j2ee[^\\\\/]*\\.jar"); int indexOfMail = findJarIndex(urlList, ".*[\\W]mail[^\\\\/]*\\.jar"); int indexOfActivation = findJarIndex(urlList, ".*[\\W]activation.*\\.jar"); int indexMaxMailOrActivation = Math.max(indexOfMail, indexOfActivation); if ((indexOfJ2EE == -1) || (indexMaxMailOrActivation == -1)) { System.err.println("Cannot find j2ee or mail|activation, do not adj. index."); } else { if (indexOfJ2EE > indexMaxMailOrActivation) { System.err.println("J2ee is after mail|activation, do not adj. index."); } else { URL j2eeUrl = urlList.remove(indexOfJ2EE); urlList.add(j2eeUrl); System.err.println("Classpath url order has been adjusted:" + urlList); } } // adjust classes and classes.test try { if (urlList.size() >= 2) { URL url1 = urlList.get(0); URL url2 = urlList.get(1); if (url1.toString().contains("/target/classes/") && url2.toString().contains("/target/classes.test/")) { urlList.add(0, urlList.remove(1)); } } } catch (Exception e) { System.err.println("Adjust classes and classes.test failed."); e.printStackTrace(); } return urlList; } // ?jar? private static int findJarIndex(List<URL> urlList, String jarPattern) { for (int i = 0; i < urlList.size(); i++) { if (Pattern.compile(jarPattern).matcher(urlList.get(i).getPath()).matches()) { return i; } } return -1; } // URLURLJAR?autoconfig?autoconfig? private static URL translateURL(URL url) throws Exception { URLClassLoader ucl = new URLClassLoader(new URL[] { url }); // URL?autoconfig List<URL> autoConfigXmlList = AutoConfigUtil.loadAllAutoConfigFilesWithFind(ucl); if ((autoConfigXmlList == null) || (autoConfigXmlList.size() == 0)) { return url; } AutoConfigMap acm = AutoConfigUtil.loadAutoConfigMapWithFind(ucl, IntlTestProperties.PROPERTIES); // ??URL boolean urlTranslated = false; // String outputPath; if ("file".equals(url.getProtocol()) && !url.toString().toLowerCase().endsWith(".jar")) { outputPath = FileUtil.convertURLToFilePath(url); } else if (url.toString().toLowerCase().endsWith(".jar")) { String fileN = FileUtil.convertURLToFile(url).getName(); String jarUrlPath = fileN + "@" + url.toString().hashCode(); jarUrlPath = jarUrlPath.replace(".jar", "").replace("alibaba", ""); outputPath = TESTCASE_JAR_TEMP_DIR + File.separator + StringUtil.replaceNoWordChars(jarUrlPath); // ?????? File signature = new File(outputPath + File.separator + TESTCASE_JAR_SIGNATURE); StringBuilder refAst = new StringBuilder(); if (isOutOfDate(signature, url, refAst)) { // JAR??JAR?JAR?? FileUtil.clearAndMakeDirs(outputPath); expandJarTo(new JarFile(FileUtil.convertURLToFile(url)), outputPath); FileUtils.writeStringToFile(signature, refAst.toString()); } urlTranslated = true; } else { throw new RuntimeException("URL protocol unknow:" + url); } // ?autoconfig? System.err.println("Auto config for:" + url); for (AutoConfigItem antxConfigResourceItem : acm.values()) { AutoConfigUtil.autoConfigFile(ucl, IntlTestProperties.PROPERTIES, antxConfigResourceItem, outputPath, true); } return urlTranslated ? (new File(outputPath)).toURI().toURL() : url; } // JAR private static void expandJarTo(JarFile jarFile, String outputPath) throws IOException { List<JarEntry> entries = CollectionUtil.toCollection(ArrayList.class, jarFile.entries()); for (JarEntry entry : entries) { if (entry.isDirectory()) { // ignore directory } else { // File efile = new File(outputPath, entry.getName()); efile.getParentFile().mkdirs(); InputStream in = new BufferedInputStream(jarFile.getInputStream(entry)); OutputStream out = new BufferedOutputStream(new FileOutputStream(efile)); IOUtils.copy(in, out); IOUtils.closeQuietly(out); IOUtils.closeQuietly(in); } } } // ?JAR? private static boolean isOutOfDate(File signature, URL jar, StringBuilder refAst) throws IOException { File jf = FileUtil.convertURLToFile(jar); long len = jf.length(); long mod = jf.lastModified(); String ast = String.valueOf(len) + "/" + String.valueOf(mod); refAst.append(ast); if (!signature.exists()) { return true; } String st = FileUtils.readFileToString(signature); return (!StringUtil.trimedIgnoreCaseEquals(st, ast)); } // ?conf, conf.test?? private static void getCallCopyAdditationURLPath() { try { boolean isRunInEclipse = (RuntimeUtil.getRuntime().getEnvironment() == RuntimeEnvironment.Eclipse); if (isRunInEclipse) { File classPath = new File(IntlTestGlobalConstants.TESTCASE_CLASSPATH); String outPath = ClassPathAccessor.getOutputPath(classPath); if (!ClassPathAccessor.isSrcConfIncluded(classPath)) { copyDirectoryTo(new File(IntlTestGlobalConstants.USER_DIR + "/src/conf"), new File(outPath)); } if (!ClassPathAccessor.isSrcConfTestIncluded(classPath)) { copyDirectoryTo(new File(IntlTestGlobalConstants.USER_DIR + "/src/conf.test"), new File(outPath)); } // ?? ClassDependcyUtil.copyFirstClassDependicies(); } boolean isRunInAntxTest = (RuntimeUtil.getRuntime().getEnvironment() == RuntimeEnvironment.AntxTest); if (isRunInAntxTest) { String outPath = IntlTestGlobalConstants.USER_DIR + "/target/classes.test"; copyDirectoryTo(new File(IntlTestGlobalConstants.USER_DIR + "/src/conf.test"), new File(outPath)); String instrumentedOutPath = IntlTestGlobalConstants.USER_DIR + "/target/instrumented-classes"; if (new File(instrumentedOutPath).exists()) { copyDirectoryTo(new File(IntlTestGlobalConstants.USER_DIR + "/src/conf.test"), new File(instrumentedOutPath)); } } } catch (Exception e) { throw ExceptionUtil.wrapToRuntimeException(e); } } // ? private static void copyDirectoryTo(File dirFrom, File dirTo) throws IOException { if (dirFrom.exists() && dirFrom.isDirectory()) { FileUtil.copyDirectory(dirFrom, dirTo, new FileFilter() { public boolean accept(File pathname) { return (!pathname.toString().contains(".svn")); } }); } } private static CopiedJDK5Manifest findSurefireBooterManifest() throws Exception { ArrayList<URL> urls = CollectionUtil.toCollection(ArrayList.class, IntlTestURLClassPath.class.getClassLoader().getResources("META-INF/MANIFEST.MF")); for (URL u : urls) { CopiedJDK5Manifest mf = new CopiedJDK5Manifest(); mf.read(u.openStream()); if ("org.apache.maven.surefire.booter.SurefireBooter" .equals(mf.getMainAttributes().getValue("Main-Class"))) { return mf; } } return null; } public static void main(String[] args) { String jarPattern = ".*[\\W]j2ee[^\\\\/]*\\.jar"; System.out.println(Pattern.compile(jarPattern) .matcher("./com/alibaba/external/java.j2ee/1.4/java.j2ee-1.4.jar").matches()); } }