📄 wrapper.java
字号:
/* * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Resin Open Source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty * of NON-INFRINGEMENT. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * Free SoftwareFoundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * * @author Scott Ferguson */package com.caucho.es.wrapper;import com.caucho.es.ESArrayWrapper;import com.caucho.es.ESBase;import com.caucho.es.ESBeanWrapper;import com.caucho.es.Global;import com.caucho.java.JavaCompiler;import com.caucho.loader.SimpleLoader;import com.caucho.log.Log;import com.caucho.server.util.CauchoSystem;import com.caucho.util.CharBuffer;import com.caucho.util.IntMap;import com.caucho.vfs.JarPath;import com.caucho.vfs.MergePath;import com.caucho.vfs.Path;import com.caucho.vfs.Vfs;import com.caucho.vfs.WriteStream;import java.beans.PropertyDescriptor;import java.io.IOException;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.lang.reflect.Modifier;import java.net.URL;import java.util.ArrayList;import java.util.HashMap;import java.util.Iterator;import java.util.Map;import java.util.logging.Logger;public class Wrapper { private static final Integer LOCK = new Integer(0); private static final Logger log = Log.open(Wrapper.class); private String name; private String javaClassName; private Class cl; private boolean isPublic; private Path dest; private WriteStream os; private ClassLoader loader; private JavaCompiler compiler; private ESBeanInfo beanInfo; private IntMap hasDispatch; private IntMap staticHasDispatch; private IntMap setDispatch; private IntMap staticSetDispatch; private IntMap methodDispatch; private IntMap staticMethodDispatch; private HashMap namedProperties; private ArrayList overloadDispatch; private int depth; private boolean isNewline; private Class esBase; /** * Creates the instance of the wrapper generator. * * @param resin the global parent object * @param cl the class to wrap. */ private Wrapper(Global resin, Class cl) { name = cl.getName().replace('/', '.'); MergePath mergePath = new MergePath(); mergePath.addClassPath(cl.getClassLoader()); Path destClass = mergePath.lookup(name.replace('.', '/') + ".class"); // technically, need to resort to dynamic. This is a cheat. if (! destClass.exists() && cl.getInterfaces().length > 0) { cl = cl.getInterfaces()[0]; name = cl.getName().replace('/', '.'); } javaClassName = toJavaClassName(name); CharBuffer cb = new CharBuffer(); for (int i = 0; i < name.length(); i++) { char ch = name.charAt(i); if (ch == '$') cb.append("_0"); else if (ch == '_') cb.append("__"); else cb.append(ch); } name = "_jsbean." + cb + "_es"; this.cl = cl; isPublic = Modifier.isPublic(cl.getModifiers()); //this.loader = resin.getParentLoader(); loader = cl.getClassLoader(); compiler = JavaCompiler.create(loader); //compiler.setEncoding("utf8"); Path workPath = CauchoSystem.getWorkPath(); dest = workPath.lookup(name.replace('.', '/') + ".java"); hasDispatch = new IntMap(); staticHasDispatch = new IntMap(); setDispatch = new IntMap(); staticSetDispatch = new IntMap(); methodDispatch = new IntMap(); staticMethodDispatch = new IntMap(); namedProperties = new HashMap(); overloadDispatch = new ArrayList(); try { esBase = Class.forName("com.caucho.es.ESBase"); } catch (Exception e) { } } public static ESBase []bean(Global resin, Class cl) throws Throwable { Wrapper wrapper = null; if (cl.isArray()) { ESBase arrayWrapper = ESArrayWrapper.wrapper(resin, cl); return new ESBase[] { arrayWrapper.getProperty("CONSTRUCTOR"), arrayWrapper }; } synchronized (LOCK) { wrapper = new Wrapper(resin, cl); ESBeanWrapper beanWrapper = wrapper.wrap(); beanWrapper.n = 0; return new ESBase[] { beanWrapper.wrapStatic(), beanWrapper }; } } /** * Creates the wrapper for a class */ private ESBeanWrapper wrap() throws Throwable { dest.getParent().mkdirs(); Path workPath = CauchoSystem.getWorkPath(); Path destClass = workPath.lookup(name.replace('.', '/') + ".class"); ClassLoader beanLoader; beanLoader = SimpleLoader.create(loader, CauchoSystem.getWorkPath(), name); ESBeanWrapper wrapper; try { Class cl = CauchoSystem.loadClass(name, false, beanLoader); wrapper = (ESBeanWrapper) cl.newInstance(); if (! wrapper.isModified() && wrapper.getVersionId() == CauchoSystem.getVersionId()) return wrapper; } catch (Throwable e) { } destClass.remove(); os = dest.openWrite(); beanInfo = ESIntrospector.getBeanInfo(cl); try { printHeader(); printConstructors(); printHasProperty(); printSetProperty(); printKeys(); printDeletes(); printMethods(); printInit(); printFooter(); } finally { os.close(); } compiler.compile(name.replace('.', '/') + ".java", null); beanLoader = SimpleLoader.create(loader, CauchoSystem.getWorkPath(), name); try { Class cl = CauchoSystem.loadClass(name, false, beanLoader); wrapper = (ESBeanWrapper) cl.newInstance(); } catch (NoClassDefFoundError e) { e.printStackTrace(); throw e; } return wrapper; } private long getSourceLastModified(Class cl) { long lastModified = 0; String classPath; URL resource = null; String clName = cl.getName().replace('.', '/') + ".class"; String name; if (loader != null) resource = loader.getResource(clName); String fileName = resource != null ? resource.toExternalForm() : null; // XXX: need to implement jar: filesystem if (resource == null || fileName.startsWith("systemresource:") || fileName.startsWith("jar:")) return getClassPathLastModified(cl); Path path = Vfs.lookup(fileName); if (path != null && path.canRead()) return path.getLastModified(); else return 0; } private long getClassPathLastModified(Class cl) { String clName = cl.getName().replace('.', '/') + ".class"; String classPath = System.getProperty("java.class.path"); char sep = CauchoSystem.getPathSeparatorChar(); int head = 0; int tail; for (; (tail = classPath.indexOf(sep, head)) >= 0; head = tail + 1) { String name = classPath.substring(head, tail); Path path = Vfs.lookupNative(name); if (name.endsWith(".jar") || name.endsWith(".zip")) path = JarPath.create(path); if (path != null && path.lookup(clName).canRead()) { return path.lookup(clName).getLastModified(); } } String name = classPath.substring(head); Path path = Vfs.lookupNative(name); if (name.endsWith(".jar") || name.endsWith(".zip")) path = JarPath.create(path); if (path != null && path.lookup(clName).canRead()) return path.lookup(clName).getLastModified(); return 0; } private void printHeader() throws IOException { int p = name.lastIndexOf('.'); String pkg = name.substring(0, p); String clName = name.substring(p + 1); println("package " + pkg + ";"); println("import com.caucho.es.*;"); Iterator iter = beanInfo.getNonPkgClasses().iterator(); while (iter.hasNext()) { String name = (String) iter.next(); println("import " + name + ";"); } println(); println("public class " + clName + " extends ESBeanWrapper {"); pushDepth(); if (isPublic) println("private " + javaClassName + " _value;"); println(); println("public long getVersionId() { return " + CauchoSystem.getVersionId() + "L; }"); println(); println("protected ESBeanWrapper dup()"); println("{"); println(" return new " + clName + "();"); println("}"); println(); println("public ESBeanWrapper wrap(Object value)"); println("{"); pushDepth(); println("if (value == null) throw new NullPointerException();"); println(name + " child = new " + name + "();"); println("child.value = value;"); if (isPublic) println("child._value = (" + javaClassName + ") value;"); println("child.hasDispatch = instanceHasDispatch;"); println("child.setDispatch = instanceSetDispatch;"); println("child.methodDispatch = instanceMethodDispatch;"); println("child.n = -1;"); println("return child;"); popDepth(); println("}"); println(); println("public ESBeanWrapper wrapStatic()"); println("{"); pushDepth(); println(name + " child = new " + name + "();"); println("child.hasDispatch = staticHasDispatch;"); println("child.setDispatch = staticSetDispatch;"); println("child.methodDispatch = staticMethodDispatch;"); println("child.n = -2;"); println("child.name = \"" + javaClassName + "\";"); println("try {"); println(" child.value = Class.forName(child.name);"); println("} catch (Exception e) {}"); println("return child;"); popDepth(); println("}"); println(); println("public Class getJavaType()"); println("{"); pushDepth(); println("return value.getClass();"); popDepth(); println("}"); } private void printConstructors() throws IOException { println(); println("public ESBase construct(Call call, int length)"); println(" throws Throwable"); println("{"); pushDepth(); println("if (n != -2)"); println(" throw new ESException(\"can't create `" + javaClassName + "'\");"); println(); if (printMethodConstructor()) { popDepth(); println("}"); return; } ArrayList overload = beanInfo.getConstructors(); if (Modifier.isAbstract(cl.getModifiers())) overload = null; if (overload == null || overload.size() == 0) { println(" throw new ESException(\"can't create `" + javaClassName + "'\");"); } else { Constructor last = null; for (int i = 0; i < overload.size(); i++) { if (overload.get(i) instanceof Constructor) last = (Constructor) overload.get(i); } for (int i = 0; i < overload.size(); i++) { Object o = overload.get(i); if (! (o instanceof Constructor)) continue; Constructor constructor = (Constructor) o; if (constructor != last) { println("if (length <= " + i + ")"); print(" "); } print("return wrap(new " + javaClassName + "("); Class []param = constructor.getParameterTypes(); for (int j = 0; j < param.length; j++) { if (j > 0) print(", "); printArgToJava(param[j], j); } println("));"); } if (last == null) println("throw new ESException(\"can't create `" + javaClassName + "'\");"); } popDepth(); println("}"); } private boolean printMethodConstructor() throws IOException { ArrayList overload = (ArrayList) beanInfo._staticMethodMap.get("create"); if (overload != null) { printMethod(Integer.MIN_VALUE, "create", overload, null); return true; } else return false; } /** * Print the code for accessing properties. */ private void printHasProperty() throws IOException { println(); println("public ESBase hasProperty(ESString name)"); println(" throws Throwable"); println("{"); pushDepth(); println("ESBase temp;"); println("switch (hasDispatch.get(name)) {"); PropertyDescriptor []props = beanInfo.getPropertyDescriptors(); int index = 1; for (int i = 0; i < props.length; i++) { if (props[i] instanceof NamedPropertyDescriptor) index = doHasNamedProperty(index, (NamedPropertyDescriptor) props[i]); else if (props[i] instanceof ESIndexedPropertyDescriptor) index = doHasIndexProperty(index, (ESIndexedPropertyDescriptor) props[i]); else if (props[i] instanceof ESPropertyDescriptor) index = doHasProperty(index, (ESPropertyDescriptor) props[i]); else throw new RuntimeException(); } println("default:"); println(" return ESBase.esEmpty;"); println("}"); popDepth(); println("}"); } private int doHasIndexProperty(int i, ESIndexedPropertyDescriptor prop) throws IOException { Named named = new Named(prop.getName(), namedProperties.size()); int n = named.n; namedProperties.put(prop.getName(), named); hasDispatch.put(prop.getName(), i); println("case " + i + ":"); pushDepth(); println("if (name" + n + " == null) {"); println(" name" + n + " = new " + name + "();"); println(" name" + n + ".value = value;"); if (isPublic) println(" name" + n + "._value = _value;"); println(" name" + n + ".hasDispatch = has" + n + ";"); println(" name" + n + ".setDispatch = set" + n + ";"); println(" name" + n + ".delId = " + n + ";"); println("}"); println("return name" + n + ";"); popDepth(); i += 1; ESMethodDescriptor md = prop.getESReadMethod(); if (md == null) return i; println("case " + i + ":"); pushDepth(); named.get = i; ESMethodDescriptor size = prop.getESSizeMethod(); if (size != null) { println("if (name.equals(LENGTH)) {"); pushDepth(); Method method = size.getMethod(); Class resultClass = method.getReturnType(); print("return "); startJavaToES(resultClass); startProp(size); print(")"); endJavaToES(resultClass); println(";"); popDepth(); println("} else {"); pushDepth(); } Method method = md.getMethod(); Class resultClass = method.getReturnType(); print("return "); startJavaToES(resultClass); int p = startProp(md); if (p > 0) print(", "); print("name.toInt32())"); endJavaToES(resultClass); println(";"); if (size != null) { popDepth(); println("}"); } popDepth(); return i + 1; } private int doHasNamedProperty(int i, NamedPropertyDescriptor prop) throws IOException { Named named = new Named(prop.getName(), namedProperties.size()); int n = named.n;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -