/*
* GNU LESSER GENERAL PUBLIC LICENSE Copyright (C) 2006 The Lobo Project
*
* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library 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. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Contact info: xamjadmin@users.sourceforge.net
*/
package org.cobra_grendel.js;
import java.lang.reflect.Method;
import org.mozilla.javascript.EvaluatorException;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import org.mozilla.javascript.WrappedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class JavaObjectWrapper extends ScriptableObject
{
private static final Logger LOGGER = LoggerFactory.getLogger(JavaObjectWrapper.class);
/**
*
*/
private static final long serialVersionUID = 3901811777319788638L;
public static Function getConstructor(final String className, final JavaClassWrapper classWrapper, final Scriptable scope)
{
return new JavaConstructorObject(className, classWrapper);
}
public static Function getConstructor(final String className, final JavaClassWrapper classWrapper, final Scriptable scope, final JavaInstantiator instantiator)
{
return new JavaConstructorObject(className, classWrapper, instantiator);
}
private final JavaClassWrapper classWrapper;
private final Object delegate;
public JavaObjectWrapper(final JavaClassWrapper classWrapper) throws InstantiationException, IllegalAccessException
{
this.classWrapper = classWrapper;
// Retaining a strong reference, but note
// that the object wrapper map uses weak keys
// and weak values.
Object delegate = this.classWrapper.newInstance();
this.delegate = delegate;
}
public JavaObjectWrapper(final JavaClassWrapper classWrapper, final Object delegate)
{
if (delegate == null)
{
throw new IllegalArgumentException("Argument delegate cannot be null.");
}
this.classWrapper = classWrapper;
// Retaining a strong reference, but note
// that the object wrapper map uses weak keys
// and weak values.
this.delegate = delegate;
}
@Override
public Object get(final int index, final Scriptable start)
{
PropertyInfo pinfo = classWrapper.getIntegerIndexer();
if (pinfo == null)
{
return super.get(index, start);
}
else
{
try
{
Method getter = pinfo.getGetter();
if (getter == null)
{
throw new EvaluatorException("Indexer is write-only");
}
// Cannot retain delegate with a strong reference.
Object javaObject = getJavaObject();
if (javaObject == null)
{
throw new IllegalStateException("Java object (class=" + classWrapper + ") is null.");
}
Object raw = getter.invoke(javaObject, new Object[] { new Integer(index) });
return JavaScript.getInstance().getJavascriptObject(raw, getParentScope());
}
catch (Exception err)
{
throw new WrappedException(err);
}
}
}
@Override
public Object get(final String name, final Scriptable start)
{
PropertyInfo pinfo = classWrapper.getProperty(name);
if (pinfo != null)
{
Method getter = pinfo.getGetter();
if (getter == null)
{
throw new EvaluatorException("Property '" + name + "' is not readable");
}
try
{
// Cannot retain delegate with a strong reference.
Object javaObject = getJavaObject();
if (javaObject == null)
{
throw new IllegalStateException("Java object (class=" + classWrapper + ") is null.");
}
Object val = getter.invoke(javaObject, (Object[]) null);
return JavaScript.getInstance().getJavascriptObject(val, start.getParentScope());
}
catch (Exception err)
{
throw new WrappedException(err);
}
}
else
{
Function f = classWrapper.getFunction(name);
if (f != null)
{
return f;
}
else
{
PropertyInfo ni = classWrapper.getNameIndexer();
if (ni != null)
{
Method getter = ni.getGetter();
if (getter != null)
{
// Cannot retain delegate with a strong reference.
Object javaObject = getJavaObject();
if (javaObject == null)
{
throw new IllegalStateException("Java object (class=" + classWrapper + ") is null.");
}
try
{
Object val = getter.invoke(javaObject, new Object[] { name });
if (val == null)
{
// There might not be an indexer setter.
return super.get(name, start);
}
else
{
return JavaScript.getInstance().getJavascriptObject(val, start.getParentScope());
}
}
catch (Exception err)
{
throw new WrappedException(err);
}
}
else
{
return super.get(name, start);
}
}
else
{
return super.get(name, start);
}
}
}
}
@Override
public String getClassName()
{
return classWrapper.getClassName();
}
@Override
public java.lang.Object getDefaultValue(final java.lang.Class hint)
{
LOGGER.info("getDefaultValue(): hint=" + hint + ",this=" + getJavaObject());
if (hint == null || String.class.equals(hint))
{
Object javaObject = getJavaObject();
if (javaObject == null)
{
throw new IllegalStateException("Java object (class=" + classWrapper + ") is null.");
}
return javaObject.toString();
}
else if (Number.class.isAssignableFrom(hint))
{
Object javaObject = getJavaObject();
if (javaObject instanceof Number)
{
return javaObject;
}
else if (javaObject instanceof String)
{
return Double.valueOf((String) javaObject);
}
else
{
return super.getDefaultValue(hint);
}
}
else
{
return super.getDefaultValue(hint);
}
}
/**
* Returns the Java object.
*
* @return An object or <code>null</code> if garbage collected.
*/
public Object getJavaObject()
{
// Cannot retain delegate with a strong reference.
return delegate;
}
@Override
public void put(final int index, final Scriptable start, final Object value)
{
PropertyInfo pinfo = classWrapper.getIntegerIndexer();
if (pinfo == null)
{
super.put(index, start, value);
}
else
{
try
{
Method setter = pinfo.getSetter();
if (setter == null)
{
throw new EvaluatorException("Indexer is read-only");
}
Object actualValue;
actualValue = JavaScript.getInstance().getJavaObject(value, pinfo.getPropertyType());
setter.invoke(getJavaObject(), new Object[] { new Integer(index), actualValue });
}
catch (Exception err)
{
throw new WrappedException(err);
}
}
}
@Override
public void put(final String name, final Scriptable start, final Object value)
{
PropertyInfo pinfo = classWrapper.getProperty(name);
if (pinfo != null)
{
Method setter = pinfo.getSetter();
if (setter == null)
{
throw new EvaluatorException("Property '" + name + "' is not settable in " + classWrapper.getClassName() + ".");
}
try
{
Object actualValue;
actualValue = JavaScript.getInstance().getJavaObject(value, pinfo.getPropertyType());
setter.invoke(getJavaObject(), new Object[] { actualValue });
}
catch (IllegalArgumentException iae)
{
Exception newException = new IllegalArgumentException("Property named '" + name + "' could not be set with value " + value + ".", iae);
throw new WrappedException(newException);
}
catch (Exception err)
{
throw new WrappedException(err);
}
}
else
{
PropertyInfo ni = classWrapper.getNameIndexer();
if (ni != null)
{
Method setter = ni.getSetter();
if (setter != null)
{
try
{
Object actualValue;
actualValue = JavaScript.getInstance().getJavaObject(value, ni.getPropertyType());
setter.invoke(getJavaObject(), new Object[] { name, actualValue });
}
catch (Exception err)
{
throw new WrappedException(err);
}
}
else
{
super.put(name, start, value);
}
}
else
{
super.put(name, start, value);
}
}
}
@Override
public String toString()
{
Object javaObject = getJavaObject();
String type = javaObject == null ? "<null>" : javaObject.getClass().getName();
return "JavaObjectWrapper[object=" + getJavaObject() + ",type=" + type + "]";
}
}