package php.runtime.loader; import php.runtime.env.CompileScope; import php.runtime.env.Context; import php.runtime.env.Environment; import php.runtime.env.handler.EntityFetchHandler; import php.runtime.exceptions.CriticalException; import php.runtime.loader.dump.ModuleDumper; import php.runtime.reflection.ClassEntity; import php.runtime.reflection.FunctionEntity; import php.runtime.reflection.ModuleEntity; import php.runtime.reflection.helper.ClosureEntity; import php.runtime.reflection.helper.GeneratorEntity; import java.io.DataInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.*; public class StandaloneLoader { protected final CompileScope scope; protected final Environment env; private ClassLoader classLoader; protected final Map<String, Module> classes; protected final Map<String, Module> functions; protected final Map<String, Module> constants; protected final Map<String, Module> modules; public StandaloneLoader() { scope = new CompileScope(); env = new Environment(scope, System.out); env.getDefaultBuffer().setImplicitFlush(true); classes = new HashMap<String, Module>(); functions = new HashMap<String, Module>(); constants = new HashMap<String, Module>(); modules = new HashMap<String, Module>(); scope.addClassEntityFetchHandler(new EntityFetchHandler() { @Override public void fetch(CompileScope scope, String originName, String name) { ModuleEntity module = fetchClass(name); if (module != null) { loadModule(module); scope.loadModule(module, false); scope.registerModule(module); } } }); scope.addFunctionEntityFetchHandler(new EntityFetchHandler() { @Override public void fetch(CompileScope scope, String originName, String name) { ModuleEntity module = fetchFunction(name); if (module != null) { loadModule(module); scope.loadModule(module, false); scope.registerModule(module); } } }); scope.addConstantEntityFetchHandler(new EntityFetchHandler() { @Override public void fetch(CompileScope scope, String originName, String name) { ModuleEntity module = fetchConstant(name); if (module != null) { loadModule(module); scope.loadModule(module, false); scope.registerModule(module); } } }); } public StandaloneLoader(ClassLoader classLoader) { this(); this.setClassLoader(classLoader); } public ClassLoader getClassLoader() { return classLoader; } public void setClassLoader(ClassLoader classLoader) { this.classLoader = classLoader; this.scope.setNativeClassLoader(classLoader); } public Collection<InputStream> getResources(String name) { List<InputStream> result = new ArrayList<InputStream>(); try { Enumeration<URL> urls = classLoader.getResources(name); while (urls.hasMoreElements()) { URL url = urls.nextElement(); result.add(url.openStream()); } return result; } catch (IOException e) { return Collections.emptyList(); //throw new LaunchException(e.getMessage()); } } protected void loadExtension(InputStream stream) { if (stream != null) { Scanner scanner = new Scanner(stream); while (scanner.hasNextLine()) { String line = scanner.nextLine().trim(); if (!line.isEmpty()) { scope.registerExtension(line); } } } } public void loadExtensions() { if (classLoader == null) { throw new NullPointerException("classLoader is null"); } loadExtension(classLoader.getResourceAsStream("JPHP-INF/standalone.extensions.list")); for (InputStream stream : getResources("JPHP-INF/extensions.list")) { loadExtension(stream); } } public void loadLibrary() throws IOException { if (classLoader == null) { throw new NullPointerException("classLoader is null"); } this.loadClassesDump(classLoader.getResourceAsStream("JPHP-INF/classes.dump")); } public void run() { run("JPHP-INF/.bootstrap"); } public void run(String bootstrapScriptName) { loadExtensions(); try { loadLibrary(); ModuleEntity bootstrap = fetchModule(bootstrapScriptName); if (bootstrap != null) { bootstrap.includeNoThrow(env); } else { System.out.println("(!) Cannot find bootstrap script."); } } catch (IOException e) { throw new CriticalException(e); } } protected ModuleEntity _fetch(String name, Map<String, Module> source) { Module module = source.get(name); if (module == null) { return null; } InputStream input = classLoader.getResourceAsStream(module.internalName + ".dump"); if (input == null) { return null; } ModuleDumper moduleDumper = new ModuleDumper(new Context(new File(module.name)), env, true); try { return moduleDumper.load(input); } catch (IOException e) { throw new RuntimeException(e); } } public ModuleEntity fetchModule(String name) { ModuleEntity entity = _fetch(name.toLowerCase(), modules); if (entity != null) { loadModule(entity); scope.loadModule(entity, false); scope.addUserModule(entity); } return entity; } public ModuleEntity fetchClass(String name) { return _fetch(name.toLowerCase(), classes); } public ModuleEntity fetchFunction(String name) { return _fetch(name.toLowerCase(), functions); } public ModuleEntity fetchConstant(String name) { return _fetch(name, constants); } public CompileScope getScope() { return scope; } protected void loadClassesDump(InputStream input) throws IOException { DataInputStream classesDump = new DataInputStream(input); int size = classesDump.readInt(); for (int i = 0; i < size; i++) { String name = classesDump.readUTF(); String internalName = classesDump.readUTF(); // classes int classesSize = classesDump.readInt(); Set<String> classes = new HashSet<String>(); for (int j = 0; j < classesSize; j++) { classes.add(classesDump.readUTF()); } // functions int functionsSize = classesDump.readInt(); Set<String> functions = new HashSet<String>(); for (int j = 0; j < functionsSize; j++) { functions.add(classesDump.readUTF()); } // constants int constantSize = classesDump.readInt(); Set<String> constants = new HashSet<String>(); for (int j = 0; j < constantSize; j++) { constants.add(classesDump.readUTF()); } Module module = new Module(name, internalName, classes, functions, constants); registerModule(module); } } protected void loadModule(ModuleEntity moduleEntity) { try { moduleEntity.setNativeClazz(classLoader.loadClass(moduleEntity.getInternalName())); for (FunctionEntity functionEntity : moduleEntity.getFunctions()) { functionEntity.setNativeClazz( classLoader.loadClass(functionEntity.getInternalName()) ); } for (ClassEntity classEntity : moduleEntity.getClasses()) { classEntity.setNativeClazz( classLoader.loadClass(classEntity.getCompiledInternalName()) ); } for (ClosureEntity closureEntity : moduleEntity.getClosures()) { closureEntity.setNativeClazz( classLoader.loadClass(closureEntity.getInternalName()) ); } for (GeneratorEntity generatorEntity : moduleEntity.getGenerators()) { generatorEntity.setNativeClazz( classLoader.loadClass(generatorEntity.getInternalName()) ); } } catch (ClassNotFoundException e) { throw new RuntimeException(e); } } protected void registerModule(Module module) { for (String name : module.classes) { classes.put(name.toLowerCase(), module); } for (String name : module.functions) { functions.put(name.toLowerCase(), module); } for (String name : module.constants) { constants.put(name, module); } String name = module.name; if (name.endsWith(".php")) { name = name.substring(0, name.lastIndexOf(".php")); } modules.put(name.toLowerCase(), module); } public Environment getScopeEnvironment() { return env; } protected static class Module { public final String name; public final String internalName; public final Set<String> classes; public final Set<String> functions; public final Set<String> constants; public Module(String name, String internalName, Set<String> classes, Set<String> functions, Set<String> constants) { this.name = name; this.internalName = internalName; this.classes = classes; this.functions = functions; this.constants = constants; } } }