⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 luaobject.java

📁 luajava应用
💻 JAVA
字号:
/*
 * $Id: LuaObject.java,v 1.6 2006/12/22 14:06:40 thiago Exp $
 * Copyright (C) 2003-2007 Kepler Project.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

package org.keplerproject.luajava;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.StringTokenizer;

/**
 * This class represents a Lua object of any type. A LuaObject is constructed by a {@link LuaState} object using one of
 * the four methods:
 * <ul>
 * <li>{@link LuaState#getLuaObject(String globalName)}</li>
 * <li>{@link LuaState#getLuaObject(LuaObject parent, String name)}</li>
 * <li>{@link LuaState#getLuaObject(LuaObject parent, Number name)}</li>
 * <li>{@link LuaState#getLuaObject(LuaObject parent, LuaObject name)}</li>
 * <li>{@link LuaState#getLuaObject(int index)}</li>
 * </ul>
 * The LuaObject will represent only the object itself, not a variable or a stack index, so when you change a string,
 * remember that strings are immutable objects in Lua, and the LuaObject you have will represent the old one.
 * 
 * <h2>Proxies</h2>
 * 
 * LuaJava allows you to implement a class in Lua, like said before. If you want to create this proxy from Java, you
 * should have a LuaObject representing the table that has the functions that implement the interface. From this
 * LuaObject you can call the <code>createProxy(String implements)</code>. This method receives the string with the
 * name of the interfaces implemented by the object separated by comma.
 * 
 * @author Rizzato
 * @author Thiago Ponte
 */
public class LuaObject
{
	protected Integer ref;

	protected LuaState L;

	/**
	 * Creates a reference to an object in the variable globalName
	 * 
	 * @param L
	 * @param globalName
	 */
	protected LuaObject(LuaState L, String globalName)
	{
		synchronized (L)
		{
			this.L = L;
			L.getGlobal(globalName);
			registerValue(-1);
			L.pop(1);
		}
	}

	/**
	 * Creates a reference to an object inside another object
	 * 
	 * @param parent
	 *            The Lua Table or Userdata that contains the Field.
	 * @param name
	 *            The name that index the field
	 */
	protected LuaObject(LuaObject parent, String name) throws LuaException
	{
		synchronized (parent.getLuaState())
		{
			this.L = parent.getLuaState();

			if (!parent.isTable() && !parent.isUserdata())
			{
				throw new LuaException("Object parent should be a table or userdata .");
			}

			parent.push();
			L.pushString(name);
			L.getTable(-2);
			L.remove(-2);
			registerValue(-1);
			L.pop(1);
		}
	}

	/**
	 * This constructor creates a LuaObject from a table that is indexed by a number.
	 * 
	 * @param parent
	 *            The Lua Table or Userdata that contains the Field.
	 * @param name
	 *            The name (number) that index the field
	 * @throws LuaException
	 *             When the parent object isn't a Table or Userdata
	 */
	protected LuaObject(LuaObject parent, Number name) throws LuaException
	{
		synchronized (parent.getLuaState())
		{
			this.L = parent.getLuaState();
			if (!parent.isTable() && !parent.isUserdata())
				throw new LuaException("Object parent should be a table or userdata .");

			parent.push();
			L.pushNumber(name.doubleValue());
			L.getTable(-2);
			L.remove(-2);
			registerValue(-1);
			L.pop(1);
		}
	}

	/**
	 * This constructor creates a LuaObject from a table that is indexed by a LuaObject.
	 * 
	 * @param parent
	 *            The Lua Table or Userdata that contains the Field.
	 * @param name
	 *            The name (LuaObject) that index the field
	 * @throws LuaException
	 *             When the parent object isn't a Table or Userdata
	 */
	protected LuaObject(LuaObject parent, LuaObject name) throws LuaException
	{
		if (parent.getLuaState() != name.getLuaState())
			throw new LuaException("LuaStates must be the same!");
		synchronized (parent.getLuaState())
		{
			if (!parent.isTable() && !parent.isUserdata())
				throw new LuaException("Object parent should be a table or userdata .");

			this.L = parent.getLuaState();

			parent.push();
			name.push();
			L.getTable(-2);
			L.remove(-2);
			registerValue(-1);
			L.pop(1);
		}
	}

	/**
	 * Creates a reference to an object in the given index of the stack
	 * 
	 * @param L
	 * @param index
	 *            of the object on the lua stack
	 */
	protected LuaObject(LuaState L, int index)
	{
		synchronized (L)
		{
			this.L = L;

			registerValue(index);
		}
	}

	/**
	 * Gets the Object's State
	 */
	public LuaState getLuaState()
	{
		return L;
	}

	/**
	 * Creates the reference to the object in the registry table
	 * 
	 * @param index
	 *            of the object on the lua stack
	 */
	private void registerValue(int index)
	{
		synchronized (L)
		{
			L.pushValue(index);
			int key = L.Lref(LuaState.LUA_REGISTRYINDEX.intValue());
			ref = new Integer(key);
		}
	}

	protected void finalize()
	{
		try
		{
			synchronized (L)
			{
				if (L.getCPtrPeer() != 0)
					L.LunRef(LuaState.LUA_REGISTRYINDEX.intValue(), ref.intValue());
			}
		}
		catch (Exception e)
		{
			System.err.println("Unable to release object " + ref);
		}
	}

	/**
	 * Pushes the object represented by <code>this<code> into L's stack
	 */
	public void push()
	{
		L.rawGetI(LuaState.LUA_REGISTRYINDEX.intValue(), ref.intValue());
	}

	public boolean isNil()
	{
		synchronized (L)
		{
			push();
			boolean bool = L.isNil(-1);
			L.pop(1);
			return bool;
		}
	}

	public boolean isBoolean()
	{
		synchronized (L)
		{
			push();
			boolean bool = L.isBoolean(-1);
			L.pop(1);
			return bool;
		}
	}

	public boolean isNumber()
	{
		synchronized (L)
		{
			push();
			boolean bool = L.isNumber(-1);
			L.pop(1);
			return bool;
		}
	}

	public boolean isString()
	{
		synchronized (L)
		{
			push();
			boolean bool = L.isString(-1);
			L.pop(1);
			return bool;
		}
	}

	public boolean isFunction()
	{
		synchronized (L)
		{
			push();
			boolean bool = L.isFunction(-1);
			L.pop(1);
			return bool;
		}
	}

	public boolean isJavaObject()
	{
		synchronized (L)
		{
			push();
			boolean bool = L.isObject(-1);
			L.pop(1);
			return bool;
		}
	}

	public boolean isJavaFunction()
	{
		synchronized (L)
		{
			push();
			boolean bool = L.isJavaFunction(-1);
			L.pop(1);
			return bool;
		}
	}

	public boolean isTable()
	{
		synchronized (L)
		{
			push();
			boolean bool = L.isTable(-1);
			L.pop(1);
			return bool;
		}
	}

	public boolean isUserdata()
	{
		synchronized (L)
		{
			push();
			boolean bool = L.isUserdata(-1);
			L.pop(1);
			return bool;
		}
	}

	public int type()
	{
		synchronized (L)
		{
			push();
			int type = L.type(-1);
			L.pop(1);
			return type;
		}
	}

	public boolean getBoolean()
	{
		synchronized (L)
		{
			push();
			boolean bool = L.toBoolean(-1);
			L.pop(1);
			return bool;
		}
	}

	public double getNumber()
	{
		synchronized (L)
		{
			push();
			double db = L.toNumber(-1);
			L.pop(1);
			return db;
		}
	}

	public String getString()
	{
		synchronized (L)
		{
			push();
			String str = L.toString(-1);
			L.pop(1);
			return str;
		}
	}

	public Object getObject() throws LuaException
	{
		synchronized (L)
		{
			push();
			Object obj = L.getObjectFromUserdata(-1);
			L.pop(1);
			return obj;
		}
	}

	/**
	 * If <code>this<code> is a table or userdata tries to set
	 * a field value.
	 */
	public LuaObject getField(String field) throws LuaException
	{
		return L.getLuaObject(this, field);
	}

	/**
	 * Calls the object represented by <code>this</code> using Lua function pcall.
	 * 
	 * @param args -
	 *            Call arguments
	 * @param nres -
	 *            Number of objects returned
	 * @return Object[] - Returned Objects
	 * @throws LuaException
	 */
	public Object[] call(Object[] args, int nres) throws LuaException
	{
		synchronized (L)
		{
			if (!isFunction() && !isTable() && !isUserdata())
				throw new LuaException("Invalid object. Not a function, table or userdata .");

			int top = L.getTop();
			push();
			int nargs;
			if (args != null)
			{
				nargs = args.length;
				for (int i = 0; i < nargs; i++)
				{
					Object obj = args[i];
					L.pushObjectValue(obj);
				}
			}
			else
				nargs = 0;

			int err = L.pcall(nargs, nres, 0);

			if (err != 0)
			{
				String str;
				if (L.isString(-1))
				{
					str = L.toString(-1);
					L.pop(1);
				}
				else
					str = "";

				if (err == LuaState.LUA_ERRRUN.intValue())
				{
					str = "Runtime error. " + str;
				}
				else if (err == LuaState.LUA_ERRMEM.intValue())
				{
					str = "Memory allocation error. " + str;
				}
				else if (err == LuaState.LUA_ERRERR.intValue())
				{
					str = "Error while running the error handler function. " + str;
				}
				else
				{
					str = "Lua Error code " + err + ". " + str;
				}

				throw new LuaException(str);
			}

			if (nres == LuaState.LUA_MULTRET.intValue())
				nres = L.getTop() - top;
			if (L.getTop() - top < nres)
			{
				throw new LuaException("Invalid Number of Results .");
			}

			Object[] res = new Object[nres];

			for (int i = nres; i > 0; i--)
			{
				res[i - 1] = L.toJavaObject(-1);
				L.pop(1);
			}
			return res;
		}
	}

	/**
	 * Calls the object represented by <code>this</code> using Lua function pcall. Returns 1 object
	 * 
	 * @param args -
	 *            Call arguments
	 * @return Object - Returned Object
	 * @throws LuaException
	 */
	public Object call(Object[] args) throws LuaException
	{
		return call(args, 1)[0];
	}

	public String toString()
	{
		synchronized (L)
		{
			try
			{
				if (isNil())
					return "nil";
				else if (isBoolean())
					return String.valueOf(getBoolean());
				else if (isNumber())
					return String.valueOf(getNumber());
				else if (isString())
					return getString();
				else if (isFunction())
					return "Lua Function";
				else if (isJavaObject())
					return getObject().toString();
				else if (isUserdata())
					return "Userdata";
				else if (isTable())
					return "Lua Table";
				else if (isJavaFunction())
					return "Java Function";
				else
					return null;
			}
			catch (LuaException e)
			{
				return null;
			}
		}
	}

	/**
	 * Function that creates a java proxy to the object represented by <code>this</code>
	 * 
	 * @param implem
	 *            Interfaces that are implemented, separated by <code>,</code>
	 */
	public Object createProxy(String implem) throws ClassNotFoundException, LuaException
	{
		synchronized (L)
		{
			if (!isTable())
				throw new LuaException("Invalid Object. Must be Table.");

			StringTokenizer st = new StringTokenizer(implem, ",");
			Class[] interfaces = new Class[st.countTokens()];
			for (int i = 0; st.hasMoreTokens(); i++)
				interfaces[i] = Class.forName(st.nextToken());

			InvocationHandler handler = new LuaInvocationHandler(this);

			return Proxy.newProxyInstance(this.getClass().getClassLoader(), interfaces, handler);
		}
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -