001: /*
002: * $Id: LuaJavaAPI.java,v 1.4 2006/12/22 14:06:40 thiago Exp $
003: * Copyright (C) 2003-2007 Kepler Project.
004: *
005: * Permission is hereby granted, free of charge, to any person obtaining
006: * a copy of this software and associated documentation files (the
007: * "Software"), to deal in the Software without restriction, including
008: * without limitation the rights to use, copy, modify, merge, publish,
009: * distribute, sublicense, and/or sell copies of the Software, and to
010: * permit persons to whom the Software is furnished to do so, subject to
011: * the following conditions:
012: *
013: * The above copyright notice and this permission notice shall be
014: * included in all copies or substantial portions of the Software.
015: *
016: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
017: * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
018: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
019: * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
020: * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
021: * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
022: * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
023: */
024:
025: package org.keplerproject.luajava;
026:
027: import java.lang.reflect.Constructor;
028: import java.lang.reflect.Field;
029: import java.lang.reflect.Method;
030: import java.lang.reflect.Modifier;
031:
032: /**
033: * Class that contains functions accessed by lua.
034: *
035: * @author Thiago Ponte
036: */
037: public final class LuaJavaAPI {
038:
039: private LuaJavaAPI() {
040: }
041:
042: /**
043: * Java implementation of the metamethod __index
044: *
045: * @param luaState int that indicates the state used
046: * @param obj Object to be indexed
047: * @param methodName the name of the method
048: * @return number of returned objects
049: */
050: public static int objectIndex(int luaState, Object obj,
051: String methodName) throws LuaException {
052: LuaState L = LuaStateFactory.getExistingState(luaState);
053:
054: synchronized (L) {
055: int top = L.getTop();
056:
057: Object[] objs = new Object[top - 1];
058:
059: Class clazz;
060:
061: if (obj instanceof Class) {
062: clazz = (Class) obj;
063: } else {
064: clazz = obj.getClass();
065: }
066:
067: Method[] methods = clazz.getMethods();
068: Method method = null;
069:
070: // gets method and arguments
071: for (int i = 0; i < methods.length; i++) {
072: if (!methods[i].getName().equals(methodName))
073:
074: continue;
075:
076: Class[] parameters = methods[i].getParameterTypes();
077: if (parameters.length != top - 1)
078: continue;
079:
080: boolean okMethod = true;
081:
082: for (int j = 0; j < parameters.length; j++) {
083: try {
084: objs[j] = compareTypes(L, parameters[j], j + 2);
085: } catch (Exception e) {
086: okMethod = false;
087: break;
088: }
089: }
090:
091: if (okMethod) {
092: method = methods[i];
093: break;
094: }
095:
096: }
097:
098: // If method is null means there isn't one receiving the given arguments
099: if (method == null) {
100: throw new LuaException(
101: "Invalid method call. No such method.");
102: }
103:
104: Object ret;
105: try {
106: if (Modifier.isPublic(method.getModifiers())) {
107: method.setAccessible(true);
108: }
109:
110: if (obj instanceof Class) {
111: ret = method.invoke(null, objs);
112: } else {
113: ret = method.invoke(obj, objs);
114: }
115: } catch (Exception e) {
116: throw new LuaException(e);
117: }
118:
119: // Void function returns null
120: if (ret == null) {
121: return 0;
122: }
123:
124: // push result
125: L.pushObjectValue(ret);
126:
127: return 1;
128: }
129: }
130:
131: /**
132: * Java function to be called when a java Class metamethod __index is called.
133: * This function returns 1 if there is a field with searchName and 2 if there
134: * is a method if the searchName
135: *
136: * @param luaState int that represents the state to be used
137: * @param clazz class to be indexed
138: * @param searchName name of the field or method to be accessed
139: * @return number of returned objects
140: * @throws LuaException
141: */
142: public static int classIndex(int luaState, Class clazz,
143: String searchName) throws LuaException {
144: synchronized (LuaStateFactory.getExistingState(luaState)) {
145: int res;
146:
147: res = checkField(luaState, clazz, searchName);
148:
149: if (res != 0) {
150: return 1;
151: }
152:
153: res = checkMethod(luaState, clazz, searchName);
154:
155: if (res != 0) {
156: return 2;
157: }
158:
159: return 0;
160: }
161: }
162:
163: /**
164: * Pushes a new instance of a java Object of the type className
165: *
166: * @param luaState int that represents the state to be used
167: * @param className name of the class
168: * @return number of returned objects
169: * @throws LuaException
170: */
171: public static int javaNewInstance(int luaState, String className)
172: throws LuaException {
173: LuaState L = LuaStateFactory.getExistingState(luaState);
174:
175: synchronized (L) {
176: Class clazz;
177: try {
178: clazz = Class.forName(className);
179: } catch (ClassNotFoundException e) {
180: throw new LuaException(e);
181: }
182: Object ret = getObjInstance(L, clazz);
183:
184: L.pushJavaObject(ret);
185:
186: return 1;
187: }
188: }
189:
190: /**
191: * javaNew returns a new instance of a given clazz
192: *
193: * @param luaState int that represents the state to be used
194: * @param clazz class to be instanciated
195: * @return number of returned objects
196: * @throws LuaException
197: */
198: public static int javaNew(int luaState, Class clazz)
199: throws LuaException {
200: LuaState L = LuaStateFactory.getExistingState(luaState);
201:
202: synchronized (L) {
203: Object ret = getObjInstance(L, clazz);
204:
205: L.pushJavaObject(ret);
206:
207: return 1;
208: }
209: }
210:
211: /**
212: * Calls the static method <code>methodName</code> in class <code>className</code>
213: * that receives a LuaState as first parameter.
214: * @param luaState int that represents the state to be used
215: * @param className name of the class that has the open library method
216: * @param methodName method to open library
217: * @return number of returned objects
218: * @throws LuaException
219: */
220: public static int javaLoadLib(int luaState, String className,
221: String methodName) throws LuaException {
222: LuaState L = LuaStateFactory.getExistingState(luaState);
223:
224: synchronized (L) {
225: Class clazz;
226: try {
227: clazz = Class.forName(className);
228: } catch (ClassNotFoundException e) {
229: throw new LuaException(e);
230: }
231:
232: try {
233: Method mt = clazz.getMethod(methodName,
234: new Class[] { LuaState.class });
235: Object obj = mt.invoke(null, new Object[] { L });
236:
237: if (obj != null && obj instanceof Integer) {
238: return ((Integer) obj).intValue();
239: } else
240: return 0;
241: } catch (Exception e) {
242: throw new LuaException(
243: "Error on calling method. Library could not be loaded. "
244: + e.getMessage());
245: }
246: }
247: }
248:
249: private static Object getObjInstance(LuaState L, Class clazz)
250: throws LuaException {
251: synchronized (L) {
252: int top = L.getTop();
253:
254: Object[] objs = new Object[top - 1];
255:
256: Constructor[] constructors = clazz.getConstructors();
257: Constructor constructor = null;
258:
259: // gets method and arguments
260: for (int i = 0; i < constructors.length; i++) {
261: Class[] parameters = constructors[i]
262: .getParameterTypes();
263: if (parameters.length != top - 1)
264: continue;
265:
266: boolean okConstruc = true;
267:
268: for (int j = 0; j < parameters.length; j++) {
269: try {
270: objs[j] = compareTypes(L, parameters[j], j + 2);
271: } catch (Exception e) {
272: okConstruc = false;
273: break;
274: }
275: }
276:
277: if (okConstruc) {
278: constructor = constructors[i];
279: break;
280: }
281:
282: }
283:
284: // If method is null means there isn't one receiving the given arguments
285: if (constructor == null) {
286: throw new LuaException(
287: "Invalid method call. No such method.");
288: }
289:
290: Object ret;
291: try {
292: ret = constructor.newInstance(objs);
293: } catch (Exception e) {
294: throw new LuaException(e);
295: }
296:
297: if (ret == null) {
298: throw new LuaException(
299: "Couldn't instantiate java Object");
300: }
301:
302: return ret;
303: }
304: }
305:
306: /**
307: * Checks if there is a field on the obj with the given name
308: *
309: * @param luaState int that represents the state to be used
310: * @param obj object to be inspected
311: * @param fieldName name of the field to be inpected
312: * @return number of returned objects
313: */
314: public static int checkField(int luaState, Object obj,
315: String fieldName) throws LuaException {
316: LuaState L = LuaStateFactory.getExistingState(luaState);
317:
318: synchronized (L) {
319: Field field = null;
320: Class objClass;
321:
322: if (obj instanceof Class) {
323: objClass = (Class) obj;
324: } else {
325: objClass = obj.getClass();
326: }
327:
328: try {
329: field = objClass.getField(fieldName);
330: } catch (Exception e) {
331: return 0;
332: }
333:
334: if (field == null) {
335: return 0;
336: }
337:
338: Object ret = null;
339: try {
340: ret = field.get(obj);
341: } catch (Exception e1) {
342: return 0;
343: }
344:
345: if (obj == null) {
346: return 0;
347: }
348:
349: L.pushObjectValue(ret);
350:
351: return 1;
352: }
353: }
354:
355: /**
356: * Checks to see if there is a method with the given name.
357: *
358: * @param luaState int that represents the state to be used
359: * @param obj object to be inspected
360: * @param methodName name of the field to be inpected
361: * @return number of returned objects
362: */
363: public static int checkMethod(int luaState, Object obj,
364: String methodName) {
365: LuaState L = LuaStateFactory.getExistingState(luaState);
366:
367: synchronized (L) {
368: Class clazz;
369:
370: if (obj instanceof Class) {
371: clazz = (Class) obj;
372: } else {
373: clazz = obj.getClass();
374: }
375:
376: Method[] methods = clazz.getMethods();
377:
378: for (int i = 0; i < methods.length; i++) {
379: if (methods[i].getName().equals(methodName))
380: return 1;
381: }
382:
383: return 0;
384: }
385: }
386:
387: /**
388: * Function that creates an object proxy and pushes it into the stack
389: *
390: * @param luaState int that represents the state to be used
391: * @param implem interfaces implemented separated by comma (<code>,</code>)
392: * @return number of returned objects
393: * @throws LuaException
394: */
395: public static int createProxyObject(int luaState, String implem)
396: throws LuaException {
397: LuaState L = LuaStateFactory.getExistingState(luaState);
398:
399: synchronized (L) {
400: try {
401: if (!(L.isTable(2)))
402: throw new LuaException(
403: "Parameter is not a table. Can't create proxy.");
404:
405: LuaObject luaObj = L.getLuaObject(2);
406:
407: Object proxy = luaObj.createProxy(implem);
408: L.pushJavaObject(proxy);
409: } catch (Exception e) {
410: throw new LuaException(e);
411: }
412:
413: return 1;
414: }
415: }
416:
417: private static Object compareTypes(LuaState L, Class parameter,
418: int idx) throws LuaException {
419: boolean okType = true;
420: Object obj = null;
421:
422: if (L.isBoolean(idx)) {
423: if (parameter.isPrimitive()) {
424: if (parameter != Boolean.TYPE) {
425: okType = false;
426: }
427: } else if (!parameter.isAssignableFrom(Boolean.class)) {
428: okType = false;
429: }
430: obj = new Boolean(L.toBoolean(idx));
431: } else if (L.type(idx) == LuaState.LUA_TSTRING.intValue()) {
432: if (!parameter.isAssignableFrom(String.class)) {
433: okType = false;
434: } else {
435: obj = L.toString(idx);
436: }
437: } else if (L.isFunction(idx)) {
438: if (!parameter.isAssignableFrom(LuaObject.class)) {
439: okType = false;
440: } else {
441: obj = L.getLuaObject(idx);
442: }
443: } else if (L.isTable(idx)) {
444: if (!parameter.isAssignableFrom(LuaObject.class)) {
445: okType = false;
446: } else {
447: obj = L.getLuaObject(idx);
448: }
449: } else if (L.type(idx) == LuaState.LUA_TNUMBER.intValue()) {
450: Double db = new Double(L.toNumber(idx));
451:
452: obj = LuaState.convertLuaNumber(db, parameter);
453: if (obj == null) {
454: okType = false;
455: }
456: } else if (L.isUserdata(idx)) {
457: if (L.isObject(idx)) {
458: Object userObj = L.getObjectFromUserdata(idx);
459: if (!parameter.isAssignableFrom(userObj.getClass())) {
460: okType = false;
461: } else {
462: obj = userObj;
463: }
464: } else {
465: if (!parameter.isAssignableFrom(LuaObject.class)) {
466: okType = false;
467: } else {
468: obj = L.getLuaObject(idx);
469: }
470: }
471: } else if (L.isNil(idx)) {
472: obj = null;
473: } else {
474: throw new LuaException("Invalid Parameters.");
475: }
476:
477: if (!okType) {
478: throw new LuaException("Invalid Parameter.");
479: }
480:
481: return obj;
482: }
483:
484: }
|