001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.bcel.util; 020 021import java.lang.reflect.Method; 022import java.lang.reflect.Modifier; 023 024import org.apache.commons.lang3.StringUtils; 025 026/** 027 * Java interpreter replacement, i.e., wrapper that uses its own ClassLoader to modify/generate classes as they're 028 * requested. You can take this as a template for your own applications. 029 * <p> 030 * Call this wrapper with: 031 * </p> 032 * 033 * <pre> 034 * java org.apache.bcel.util.JavaWrapper <real.class.name> [arguments] 035 * </pre> 036 * <p> 037 * To use your own class loader you can set the "bcel.classloader" system property. 038 * </p> 039 * 040 * <pre> 041 * java org.apache.bcel.util.JavaWrapper -Dbcel.classloader=foo.MyLoader <real.class.name> [arguments] 042 * </pre> 043 * 044 * @see ClassLoader 045 */ 046public class JavaWrapper { 047 048 private static java.lang.ClassLoader getClassLoader() { 049 final String s = System.getProperty("bcel.classloader"); 050 if (StringUtils.isEmpty(s)) { 051 throw new IllegalStateException("The property 'bcel.classloader' must be defined"); 052 } 053 try { 054 return (java.lang.ClassLoader) Class.forName(s).getConstructor().newInstance(); 055 } catch (final Exception e) { 056 throw new IllegalStateException(e.toString(), e); 057 } 058 } 059 060 /** 061 * Default main method used as wrapper, expects the fully qualified class name of the real class as the first argument. 062 */ 063 public static void main(final String[] argv) throws Exception { 064 /* 065 * Expects class name as first argument, other arguments are by-passed. 066 */ 067 if (argv.length == 0) { 068 System.out.println("Missing class name."); 069 return; 070 } 071 final String className = argv[0]; 072 final String[] newArgv = new String[argv.length - 1]; 073 System.arraycopy(argv, 1, newArgv, 0, newArgv.length); 074 new JavaWrapper().runMain(className, newArgv); 075 } 076 077 private final java.lang.ClassLoader loader; 078 079 public JavaWrapper() { 080 this(getClassLoader()); 081 } 082 083 public JavaWrapper(final java.lang.ClassLoader loader) { 084 this.loader = loader; 085 } 086 087 /** 088 * Runs the main method of the given class with the arguments passed in argv 089 * 090 * @param className the fully qualified class name 091 * @param argv the arguments just as you would pass them directly 092 * @throws ClassNotFoundException if {@code className} can't be found. 093 */ 094 public void runMain(final String className, final String[] argv) throws ClassNotFoundException { 095 final Class<?> cl = loader.loadClass(className); 096 Method method = null; 097 try { 098 method = cl.getMethod("main", argv.getClass()); 099 /* 100 * Method main is sane ? 101 */ 102 final int m = method.getModifiers(); 103 final Class<?> r = method.getReturnType(); 104 if (!(Modifier.isPublic(m) && Modifier.isStatic(m)) || Modifier.isAbstract(m) || r != Void.TYPE) { 105 throw new NoSuchMethodException(); 106 } 107 } catch (final NoSuchMethodException no) { 108 System.out.println("In class " + className + ": public static void main(String[] argv) is not defined"); 109 return; 110 } 111 try { 112 method.invoke(null, (Object[]) argv); 113 } catch (final Exception ex) { 114 ex.printStackTrace(); 115 } 116 } 117}