You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

335 lines
11 KiB

26 years ago
26 years ago
26 years ago
26 years ago
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP version 4.0 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997, 1998, 1999, 2000 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 2.0 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available at through the world-wide-web at |
  10. | http://www.php.net/license.html. |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Author: Sam Ruby (rubys@us.ibm.com) |
  16. +----------------------------------------------------------------------+
  17. */
  18. package net.php;
  19. import java.lang.reflect.*;
  20. import java.util.*;
  21. import java.beans.*;
  22. public class reflect {
  23. static { loadLibrary("reflect"); }
  24. protected static void loadLibrary(String property) {
  25. try {
  26. ResourceBundle bundle = ResourceBundle.getBundle("net.php."+property);
  27. System.loadLibrary(bundle.getString("library"));
  28. } catch (Exception e) {
  29. e.printStackTrace();
  30. }
  31. }
  32. //
  33. // Native methods
  34. //
  35. private static native void setResultFromString(long result, byte value[]);
  36. private static native void setResultFromLong(long result, long value);
  37. private static native void setResultFromDouble(long result, double value);
  38. private static native void setResultFromBoolean(long result, boolean value);
  39. private static native void setResultFromObject(long result, Object value);
  40. private static native void setResultFromArray(long result);
  41. private static native long nextElement(long array);
  42. private static native void setException(long result, byte value[]);
  43. public static native void setEnv();
  44. //
  45. // Helper routines which encapsulate the native methods
  46. //
  47. public static void setResult(long result, Object value) {
  48. if (value == null) return;
  49. if (value instanceof java.lang.String) {
  50. setResultFromString(result, ((String)value).getBytes());
  51. } else if (value instanceof java.lang.Number) {
  52. if (value instanceof java.lang.Integer ||
  53. value instanceof java.lang.Short ||
  54. value instanceof java.lang.Byte) {
  55. setResultFromLong(result, ((Number)value).longValue());
  56. } else {
  57. /* Float, Double, BigDecimal, BigInteger, Double, Long, ... */
  58. setResultFromDouble(result, ((Number)value).doubleValue());
  59. }
  60. } else if (value instanceof java.lang.Boolean) {
  61. setResultFromBoolean(result, ((Boolean)value).booleanValue());
  62. } else if (value.getClass().isArray()) {
  63. long length = Array.getLength(value);
  64. setResultFromArray(result);
  65. for (int i=0; i<length; i++) {
  66. setResult(nextElement(result), Array.get(value, i));
  67. }
  68. } else {
  69. setResultFromObject(result, value);
  70. }
  71. }
  72. static void setException(long result, Throwable e) {
  73. if (e instanceof InvocationTargetException) {
  74. Throwable t = ((InvocationTargetException)e).getTargetException();
  75. if (t!=null) e=t;
  76. }
  77. setException(result, e.toString().getBytes());
  78. }
  79. //
  80. // Create an new instance of a given class
  81. //
  82. public static void CreateObject(String name, Object args[], long result) {
  83. try {
  84. Vector matches = new Vector();
  85. Constructor cons[] = Class.forName(name).getConstructors();
  86. for (int i=0; i<cons.length; i++) {
  87. if (cons[i].getParameterTypes().length == args.length) {
  88. matches.addElement(cons[i]);
  89. }
  90. }
  91. Constructor selected = (Constructor)select(matches, args);
  92. if (selected == null) {
  93. if (args.length > 0) {
  94. throw new InstantiationException("No matching constructor found");
  95. } else {
  96. // for classes which have no visible constructor, return the class
  97. // useful for classes like java.lang.System and java.util.Calendar.
  98. setResult(result, Class.forName(name));
  99. return;
  100. }
  101. }
  102. Object coercedArgs[] = coerce(selected.getParameterTypes(), args);
  103. setResult(result, selected.newInstance(coercedArgs));
  104. } catch (Exception e) {
  105. setException(result, e);
  106. }
  107. }
  108. //
  109. // Select the best match from a list of methods
  110. //
  111. private static Object select(Vector methods, Object args[]) {
  112. if (methods.size() == 1) return methods.firstElement();
  113. Object selected = null;
  114. int best = Integer.MAX_VALUE;
  115. for (Enumeration e = methods.elements(); e.hasMoreElements(); ) {
  116. Object element = e.nextElement();
  117. int weight=0;
  118. Class parms[] = (element instanceof Method) ?
  119. ((Method)element).getParameterTypes() :
  120. ((Constructor)element).getParameterTypes();
  121. for (int i=0; i<parms.length; i++) {
  122. if (parms[i].isInstance(args[i])) {
  123. for (Class c=parms[i]; (c=c.getSuperclass()) != null; ) {
  124. if (!c.isInstance(args[i])) break;
  125. weight++;
  126. }
  127. } else if (parms[i].isInstance("")) {
  128. if (!(args[i] instanceof byte[]))
  129. weight+=9999;
  130. } else if (parms[i].isPrimitive()) {
  131. Class c=parms[i];
  132. if (args[i] instanceof Number) {
  133. if (c==Boolean.TYPE) weight+=5;
  134. if (c==Character.TYPE) weight+=4;
  135. if (c==Byte.TYPE) weight+=3;
  136. if (c==Short.TYPE) weight+=2;
  137. if (c==Integer.TYPE) weight++;
  138. if (c==Float.TYPE) weight++;
  139. } else if (args[i] instanceof Boolean) {
  140. if (c!=Boolean.TYPE) weight+=9999;
  141. } else if (args[i] instanceof String) {
  142. if (c== Character.TYPE || ((String)args[i]).length()>0)
  143. weight+=((String)args[i]).length();
  144. else
  145. weight+=9999;
  146. } else {
  147. weight+=9999;
  148. }
  149. } else {
  150. weight+=9999;
  151. }
  152. }
  153. if (weight < best) {
  154. if (weight == 0) return element;
  155. best = weight;
  156. selected = element;
  157. }
  158. }
  159. return selected;
  160. }
  161. //
  162. // Coerce arguments when possible to conform to the argument list.
  163. // Java's reflection will automatically do widening conversions,
  164. // unfortunately PHP only supports wide formats, so to be practical
  165. // some (possibly lossy) conversions are required.
  166. //
  167. private static Object[] coerce(Class parms[], Object args[]) {
  168. Object result[] = args;
  169. for (int i=0; i<args.length; i++) {
  170. if (args[i] instanceof byte[] && !parms[i].isArray()) {
  171. result[i] = new String((byte[])args[i]);
  172. } else if (args[i] instanceof Number && parms[i].isPrimitive()) {
  173. if (result==args) result=(Object[])result.clone();
  174. Class c = parms[i];
  175. Number n = (Number)args[i];
  176. if (c == Boolean.TYPE) result[i]=new Boolean(0.0!=n.floatValue());
  177. if (c == Byte.TYPE) result[i]=new Byte(n.byteValue());
  178. if (c == Short.TYPE) result[i]=new Short(n.shortValue());
  179. if (c == Integer.TYPE) result[i]=new Integer(n.intValue());
  180. if (c == Float.TYPE) result[i]=new Float(n.floatValue());
  181. if (c == Long.TYPE && !(n instanceof Long))
  182. result[i]=new Long(n.longValue());
  183. }
  184. }
  185. return result;
  186. }
  187. //
  188. // Invoke a method on a given object
  189. //
  190. public static void Invoke
  191. (Object object, String method, Object args[], long result)
  192. {
  193. try {
  194. Vector matches = new Vector();
  195. // gather
  196. for (Class jclass = object.getClass();;jclass=(Class)object) {
  197. while (!Modifier.isPublic(jclass.getModifiers())) {
  198. // OK, some joker gave us an instance of a non-public class
  199. // This often occurs in the case of enumerators
  200. // Substitute the first public interface in its place,
  201. // and barring that, try the superclass
  202. Class interfaces[] = jclass.getInterfaces();
  203. jclass=jclass.getSuperclass();
  204. for (int i=interfaces.length; i-->0;) {
  205. if (Modifier.isPublic(interfaces[i].getModifiers())) {
  206. jclass=interfaces[i];
  207. }
  208. }
  209. }
  210. Method methods[] = jclass.getMethods();
  211. for (int i=0; i<methods.length; i++) {
  212. if (methods[i].getName().equalsIgnoreCase(method) &&
  213. methods[i].getParameterTypes().length == args.length) {
  214. matches.addElement(methods[i]);
  215. }
  216. }
  217. // try a second time with the object itself, if it is of type Class
  218. if (!(object instanceof Class) || (jclass==object)) break;
  219. }
  220. Method selected = (Method)select(matches, args);
  221. if (selected == null) throw new NoSuchMethodException(method);
  222. Object coercedArgs[] = coerce(selected.getParameterTypes(), args);
  223. setResult(result, selected.invoke(object, coercedArgs));
  224. } catch (Exception e) {
  225. setException(result, e);
  226. }
  227. }
  228. //
  229. // Get or Set a property
  230. //
  231. public static void GetSetProp
  232. (Object object, String prop, Object args[], long result)
  233. {
  234. try {
  235. for (Class jclass = object.getClass();;jclass=(Class)object) {
  236. while (!Modifier.isPublic(jclass.getModifiers())) {
  237. // OK, some joker gave us an instance of a non-public class
  238. // Substitute the first public interface in its place,
  239. // and barring that, try the superclass
  240. Class interfaces[] = jclass.getInterfaces();
  241. jclass=jclass.getSuperclass();
  242. for (int i=interfaces.length; i-->0;) {
  243. if (Modifier.isPublic(interfaces[i].getModifiers())) {
  244. jclass=interfaces[i];
  245. }
  246. }
  247. }
  248. BeanInfo beanInfo = Introspector.getBeanInfo(jclass);
  249. PropertyDescriptor props[] = beanInfo.getPropertyDescriptors();
  250. for (int i=0; i<props.length; i++) {
  251. if (props[i].getName().equalsIgnoreCase(prop)) {
  252. Method method;
  253. if (args!=null && args.length>0) {
  254. method=props[i].getWriteMethod();
  255. args = coerce(method.getParameterTypes(), args);
  256. } else {
  257. method=props[i].getReadMethod();
  258. }
  259. setResult(result, method.invoke(object, args));
  260. return;
  261. }
  262. }
  263. Field jfields[] = jclass.getFields();
  264. for (int i=0; i<jfields.length; i++) {
  265. if (jfields[i].getName().equalsIgnoreCase(prop)) {
  266. if (args!=null && args.length>0) {
  267. args = coerce(new Class[] {jfields[i].getType()}, args);
  268. jfields[i].set(object, args[0]);
  269. } else {
  270. setResult(result, jfields[i].get(object));
  271. }
  272. return;
  273. }
  274. }
  275. // try a second time with the object itself, if it is of type Class
  276. if (!(object instanceof Class) || (jclass==object)) break;
  277. }
  278. } catch (Exception e) {
  279. setException(result, e);
  280. }
  281. }
  282. //
  283. // Helper routines for the C implementation
  284. //
  285. public static Object MakeArg(boolean b) { return new Boolean(b); }
  286. public static Object MakeArg(long l) { return new Long(l); }
  287. public static Object MakeArg(double d) { return new Double(d); }
  288. }