/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-2000 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Ethan Hugg * Terry Lucas * Milen Nankov * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package org.mozilla.javascript.xml.impl.xmlbeans; import java.util.Vector; import org.mozilla.javascript.*; import org.mozilla.javascript.xml.*; import org.apache.xmlbeans.XmlCursor; class XMLList extends XMLObjectImpl implements Function { static final long serialVersionUID = -4543618751670781135L; static class AnnotationList { private Vector v; AnnotationList () { v = new Vector(); } void add (XML.XScriptAnnotation n) { v.add(n); } XML.XScriptAnnotation item(int index) { return (XML.XScriptAnnotation)(v.get(index)); } void remove (int index) { v.remove(index); } int length() { return v.size(); } }; // Fields private AnnotationList _annos; private XMLObjectImpl targetObject = null; private javax.xml.namespace.QName targetProperty = null; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Constructors // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * */ XMLList(XMLLibImpl lib) { super(lib, lib.xmlListPrototype); _annos = new AnnotationList(); } /** * * @param inputObject */ XMLList(XMLLibImpl lib, Object inputObject) { super(lib, lib.xmlListPrototype); String frag; if (inputObject == null || inputObject instanceof Undefined) { frag = ""; } else if (inputObject instanceof XML) { XML xml = (XML) inputObject; _annos = new AnnotationList(); _annos.add(xml.getAnnotation()); } else if (inputObject instanceof XMLList) { XMLList xmll = (XMLList) inputObject; _annos = new AnnotationList(); for (int i = 0; i < xmll._annos.length(); i++) { _annos.add(xmll._annos.item(i)); } } else { frag = ScriptRuntime.toString(inputObject).trim(); if (!frag.startsWith("<>")) { frag = "<>" + frag + ""; } frag = "" + frag.substring(2); if (!frag.endsWith("")) { throw ScriptRuntime.typeError("XML with anonymous tag missing end anonymous tag"); } frag = frag.substring(0, frag.length() - 3) + ""; XML orgXML = XML.createFromJS(lib, frag); // Now orphan the children and add them to our XMLList. XMLList children = orgXML.children(); _annos = new AnnotationList(); for (int i = 0; i < children._annos.length(); i++) { // Copy here is so that they'll be orphaned (parent() will be undefined) _annos.add(((XML) children.item(i).copy()).getAnnotation()); } } } // // // TargetObject/Property accessors // // /** * * @param object * @param property */ void setTargets(XMLObjectImpl object, javax.xml.namespace.QName property) { targetObject = object; targetProperty = property; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Private functions // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * * @param index * @return */ XML getXmlFromAnnotation(int index) { XML retVal; if (index >= 0 && index < length()) { XML.XScriptAnnotation anno = _annos.item(index); retVal = XML.getFromAnnotation(lib, anno); } else { retVal = null; } return retVal; } /** * * @param index */ private void internalRemoveFromList (int index) { _annos.remove(index); } /** * * @param index * @param xml */ void replace(int index, XML xml) { if (index < length()) { AnnotationList newAnnoList = new AnnotationList(); // Copy upto item to replace. for (int i = 0; i < index; i++) { newAnnoList.add(_annos.item(i)); } newAnnoList.add(xml.getAnnotation()); // Skip over old item we're going to replace we've already add new item on above line. for (int i = index + 1; i < length(); i++) { newAnnoList.add(_annos.item(i)); } _annos = newAnnoList; } } /** * * @param index * @param xml */ private void insert(int index, XML xml) { if (index < length()) { AnnotationList newAnnoList = new AnnotationList(); // Copy upto item to insert. for (int i = 0; i < index; i++) { newAnnoList.add(_annos.item(i)); } newAnnoList.add(xml.getAnnotation()); for (int i = index; i < length(); i++) { newAnnoList.add(_annos.item(i)); } _annos = newAnnoList; } } // // // methods overriding ScriptableObject // // public String getClassName () { return "XMLList"; } // // // methods overriding IdScriptableObject // // /** * * @param index * @param start * @return */ public Object get(int index, Scriptable start) { //Log("get index: " + index); if (index >= 0 && index < length()) { return getXmlFromAnnotation(index); } else { return Scriptable.NOT_FOUND; } } /** * * @param name * @param start * @return */ boolean hasXMLProperty(XMLName xmlName) { boolean result = false; // Has now should return true if the property would have results > 0 or // if it's a method name String name = xmlName.localName(); if ((getPropertyList(xmlName).length() > 0) || (getMethod(name) != NOT_FOUND)) { result = true; } return result; } /** * * @param index * @param start * @return */ public boolean has(int index, Scriptable start) { return 0 <= index && index < length(); } /** * * @param name * @param value */ void putXMLProperty(XMLName xmlName, Object value) { //Log("put property: " + name); // Special-case checks for undefined and null if (value == null) { value = "null"; } else if (value instanceof Undefined) { value = "undefined"; } if (length() > 1) { throw ScriptRuntime.typeError("Assignment to lists with more that one item is not supported"); } else if (length() == 0) { // Secret sauce for super-expandos. // We set an element here, and then add ourselves to our target. if (targetObject != null && targetProperty != null && !targetProperty.getLocalPart().equals("*")) { // Add an empty element with our targetProperty name and then set it. XML xmlValue = XML.createTextElement(lib, targetProperty, ""); addToList(xmlValue); if(xmlName.isAttributeName()) { setAttribute(xmlName, value); } else { XML xml = item(0); xml.putXMLProperty(xmlName, value); // Update the list with the new item at location 0. replace(0, item(0)); } // Now add us to our parent XMLName name2 = XMLName.formProperty(targetProperty.getNamespaceURI(), targetProperty.getLocalPart()); targetObject.putXMLProperty(name2, this); } else { throw ScriptRuntime.typeError("Assignment to empty XMLList without targets not supported"); } } else if(xmlName.isAttributeName()) { setAttribute(xmlName, value); } else { XML xml = item(0); xml.putXMLProperty(xmlName, value); // Update the list with the new item at location 0. replace(0, item(0)); } } /** * * @param name * @return */ Object getXMLProperty(XMLName name) { return getPropertyList(name); } /** * * @param index * @param value */ public void put(int index, Scriptable start, Object value) { Object parent = Undefined.instance; // Convert text into XML if needed. XMLObject xmlValue; // Special-case checks for undefined and null if (value == null) { value = "null"; } else if (value instanceof Undefined) { value = "undefined"; } if (value instanceof XMLObject) { xmlValue = (XMLObject) value; } else { if (targetProperty == null) { xmlValue = XML.createFromJS(lib, value.toString()); } else { xmlValue = XML.createTextElement(lib, targetProperty, value.toString()); } } // Find the parent if (index < length()) { parent = item(index).parent(); } else { // Appending parent = parent(); } if (parent instanceof XML) { // found parent, alter doc XML xmlParent = (XML) parent; if (index < length()) { // We're replacing the the node. XML xmlNode = getXmlFromAnnotation(index); if (xmlValue instanceof XML) { xmlNode.replaceAll((XML) xmlValue); replace(index, xmlNode); } else if (xmlValue instanceof XMLList) { // Replace the first one, and add the rest on the list. XMLList list = (XMLList) xmlValue; if (list.length() > 0) { int lastIndexAdded = xmlNode.childIndex(); xmlNode.replaceAll(list.item(0)); replace(index, list.item(0)); for (int i = 1; i < list.length(); i++) { xmlParent.insertChildAfter(xmlParent.getXmlChild(lastIndexAdded), list.item(i)); lastIndexAdded++; insert(index + i, list.item(i)); } } } } else { // Appending xmlParent.appendChild(xmlValue); addToList(xmlParent.getXmlChild(index)); } } else { // Don't all have same parent, no underlying doc to alter if (index < length()) { XML xmlNode = XML.getFromAnnotation(lib, _annos.item(index)); if (xmlValue instanceof XML) { xmlNode.replaceAll((XML) xmlValue); replace(index, xmlNode); } else if (xmlValue instanceof XMLList) { // Replace the first one, and add the rest on the list. XMLList list = (XMLList) xmlValue; if (list.length() > 0) { xmlNode.replaceAll(list.item(0)); replace(index, list.item(0)); for (int i = 1; i < list.length(); i++) { insert(index + i, list.item(i)); } } } } else { addToList(xmlValue); } } } /** * * @param name */ void deleteXMLProperty(XMLName name) { for (int i = 0; i < length(); i++) { XML xml = getXmlFromAnnotation(i); if (xml.tokenType() == XmlCursor.TokenType.START) { xml.deleteXMLProperty(name); } } } /** * * @param index */ public void delete(int index) { if (index >= 0 && index < length()) { XML xml = getXmlFromAnnotation(index); xml.remove(); internalRemoveFromList(index); } } /** * * @return */ public Object[] getIds() { Object enumObjs[]; if (prototypeFlag) { enumObjs = new Object[0]; } else { enumObjs = new Object[length()]; for (int i = 0; i < enumObjs.length; i++) { enumObjs[i] = new Integer(i); } } return enumObjs; } /** * * @return */ public Object[] getIdsForDebug() { return getIds(); } // XMLList will remove will delete all items in the list (a set delete) this differs from the XMLList delete operator. void remove () { int nLen = length(); for (int i = nLen - 1; i >= 0; i--) { XML xml = getXmlFromAnnotation(i); if (xml != null) { xml.remove(); internalRemoveFromList(i); } } } /** * * @param index * @return */ XML item (int index) { return _annos != null ? getXmlFromAnnotation(index) : XML.createEmptyXML(lib); } /** * * @param name * @param value */ private void setAttribute (XMLName xmlName, Object value) { for (int i = 0; i < length(); i++) { XML xml = getXmlFromAnnotation(i); xml.setAttribute(xmlName, value); } } /** * * @param toAdd */ void addToList(Object toAdd) { if (toAdd instanceof Undefined) { // Missing argument do nothing... return; } if (toAdd instanceof XMLList) { XMLList xmlSrc = (XMLList)toAdd; for (int i = 0; i < xmlSrc.length(); i++) { _annos.add((xmlSrc.item(i)).getAnnotation()); } } else if (toAdd instanceof XML) { _annos.add(((XML)(toAdd)).getAnnotation()); } else if (toAdd instanceof XML.XScriptAnnotation) { _annos.add((XML.XScriptAnnotation)toAdd); } } // // // Methods from section 12.4.4 in the spec // // /** * * @param toAdd */ XML addNamespace(Namespace ns) { if(length() == 1) { return getXmlFromAnnotation(0).addNamespace(ns); } else { throw ScriptRuntime.typeError("The addNamespace method works only on lists containing one item"); } } /** * * @param xml * @return */ XML appendChild(Object xml) { if (length() == 1) { return getXmlFromAnnotation(0).appendChild(xml); } else { throw ScriptRuntime.typeError("The appendChild method works only on lists containing one item"); } } /** * * @param attr * @return */ XMLList attribute(XMLName xmlName) { XMLList result = new XMLList(lib); for (int i = 0; i < length(); i++) { XML xml = getXmlFromAnnotation(i); result.addToList(xml.attribute(xmlName)); } return result; } /** * * @return */ XMLList attributes() { XMLList result = new XMLList(lib); for (int i = 0; i < length(); i++) { XML xml = getXmlFromAnnotation(i); result.addToList(xml.attributes()); } return result; } XMLList child(long index) { XMLList result = new XMLList(lib); for (int i = 0; i < length(); i++) { result.addToList(getXmlFromAnnotation(i).child(index)); } return result; } XMLList child(XMLName xmlName) { XMLList result = new XMLList(lib); for (int i = 0; i < length(); i++) { result.addToList(getXmlFromAnnotation(i).child(xmlName)); } return result; } /** * * @return */ int childIndex() { if (length() == 1) { return getXmlFromAnnotation(0).childIndex(); } else { throw ScriptRuntime.typeError("The childIndex method works only on lists containing one item"); } } /** * * @return */ XMLList children() { Vector v = new Vector(); for (int i = 0; i < length(); i++) { XML xml = getXmlFromAnnotation(i); if (xml != null) { Object o = xml.children(); if (o instanceof XMLList) { XMLList childList = (XMLList)o; int cChildren = childList.length(); for (int j = 0; j < cChildren; j++) { v.addElement(childList.item(j)); } } } } XMLList allChildren = new XMLList(lib); int sz = v.size(); for (int i = 0; i < sz; i++) { allChildren.addToList(v.get(i)); } return allChildren; } /** * * @return */ XMLList comments() { XMLList result = new XMLList(lib); for (int i = 0; i < length(); i++) { XML xml = getXmlFromAnnotation(i); result.addToList(xml.comments()); } return result; } /** * * @param xml * @return */ boolean contains(Object xml) { boolean result = false; for (int i = 0; i < length(); i++) { XML member = getXmlFromAnnotation(i); if (member.equivalentXml(xml)) { result = true; break; } } return result; } /** * * @return */ Object copy() { XMLList result = new XMLList(lib); for (int i = 0; i < length(); i++) { XML xml = getXmlFromAnnotation(i); result.addToList(xml.copy()); } return result; } /** * * @return */ XMLList descendants(XMLName xmlName) { XMLList result = new XMLList(lib); for (int i = 0; i < length(); i++) { XML xml = getXmlFromAnnotation(i); result.addToList(xml.descendants(xmlName)); } return result; } /** * * @return */ Object[] inScopeNamespaces() { if(length() == 1) { return getXmlFromAnnotation(0).inScopeNamespaces(); } else { throw ScriptRuntime.typeError("The inScopeNamespaces method works only on lists containing one item"); } } /** * * @param child * @param xml */ XML insertChildAfter(Object child, Object xml) { if (length() == 1) { return getXmlFromAnnotation(0).insertChildAfter(child, xml); } else { throw ScriptRuntime.typeError("The insertChildAfter method works only on lists containing one item"); } } /** * * @param child * @param xml */ XML insertChildBefore(Object child, Object xml) { if (length() == 1) { return getXmlFromAnnotation(0).insertChildAfter(child, xml); } else { throw ScriptRuntime.typeError("The insertChildBefore method works only on lists containing one item"); } } /** * * @return */ boolean hasOwnProperty(XMLName xmlName) { boolean hasProperty = false; if (prototypeFlag) { String property = xmlName.localName(); hasProperty = (0 != findPrototypeId(property)); } else { hasProperty = (getPropertyList(xmlName).length() > 0); } return hasProperty; } /** * * @return */ boolean hasComplexContent() { boolean complexContent; int length = length(); if (length == 0) { complexContent = false; } else if (length == 1) { complexContent = getXmlFromAnnotation(0).hasComplexContent(); } else { complexContent = false; for (int i = 0; i < length; i++) { XML nextElement = getXmlFromAnnotation(i); if (nextElement.tokenType() == XmlCursor.TokenType.START) { complexContent = true; break; } } } return complexContent; } /** * * @return */ boolean hasSimpleContent() { boolean simpleContent; int length = length(); if (length == 0) { simpleContent = true; } else if (length == 1) { simpleContent = getXmlFromAnnotation(0).hasSimpleContent(); } else { simpleContent = true; for (int i = 0; i < length; i++) { XML nextElement = getXmlFromAnnotation(i); if (nextElement.tokenType() == XmlCursor.TokenType.START) { simpleContent = false; break; } } } return simpleContent; } /** * * @return */ int length() { int result = 0; if (_annos != null) { result = _annos.length(); } return result; } /** * * @return */ String localName() { if (length() == 1) { return name().localName(); } else { throw ScriptRuntime.typeError("The localName method works only on lists containing one item"); } } /** * * @return */ QName name() { if (length() == 1) { return getXmlFromAnnotation(0).name(); } else { throw ScriptRuntime.typeError("The name method works only on lists containing one item"); } } /** * * @param prefix * @return */ Object namespace(String prefix) { if (length() == 1) { return getXmlFromAnnotation(0).namespace(prefix); } else { throw ScriptRuntime.typeError("The namespace method works only on lists containing one item"); } } /** * * @return */ Object[] namespaceDeclarations() { if (length() == 1) { return getXmlFromAnnotation(0).namespaceDeclarations(); } else { throw ScriptRuntime.typeError("The namespaceDeclarations method works only on lists containing one item"); } } /** * * @return */ Object nodeKind() { if (length() == 1) { return getXmlFromAnnotation(0).nodeKind(); } else { throw ScriptRuntime.typeError("The nodeKind method works only on lists containing one item"); } } /** * */ void normalize() { for (int i = 0; i < length(); i++) { getXmlFromAnnotation(i).normalize(); } } /** * If list is empty, return undefined, if elements have different parents return undefined, * If they all have the same parent, return that parent. * * @return */ Object parent() { Object sameParent = Undefined.instance; if ((length() == 0) && (targetObject != null) && (targetObject instanceof XML)) { sameParent = targetObject; } else { for (int i = 0; i < length(); i++) { Object currParent = getXmlFromAnnotation(i).parent(); if (i == 0) { // Set the first for the rest to compare to. sameParent = currParent; } else if (sameParent != currParent) { sameParent = Undefined.instance; break; } } } // If everything in the list is the sameParent then return that as the parent. return sameParent; } /** * * @param xml * @return */ XML prependChild(Object xml) { if (length() == 1) { return getXmlFromAnnotation(0).prependChild(xml); } else { throw ScriptRuntime.typeError("The prependChild method works only on lists containing one item"); } } /** * * @return */ Object processingInstructions(XMLName xmlName) { XMLList result = new XMLList(lib); for (int i = 0; i < length(); i++) { XML xml = getXmlFromAnnotation(i); result.addToList(xml.processingInstructions(xmlName)); } return result; } /** * * @param name * @return */ boolean propertyIsEnumerable(Object name) { long index; if (name instanceof Integer) { index = ((Integer)name).intValue(); } else if (name instanceof Number) { double x = ((Number)name).doubleValue(); index = (long)x; if (index != x) { return false; } if (index == 0 && 1.0 / x < 0) { // Negative 0 return false; } } else { String s = ScriptRuntime.toString(name); index = ScriptRuntime.testUint32String(s); } return (0 <= index && index < length()); } /** * * @param ns */ XML removeNamespace(Namespace ns) { if(length() == 1) { return getXmlFromAnnotation(0).removeNamespace(ns); } else { throw ScriptRuntime.typeError("The removeNamespace method works only on lists containing one item"); } } XML replace(long index, Object xml) { if (length() == 1) { return getXmlFromAnnotation(0).replace(index, xml); } else { throw ScriptRuntime.typeError("The replace method works only on lists containing one item"); } } /** * * @param propertyName * @param xml * @return */ XML replace(XMLName xmlName, Object xml) { if (length() == 1) { return getXmlFromAnnotation(0).replace(xmlName, xml); } else { throw ScriptRuntime.typeError("The replace method works only on lists containing one item"); } } /** * * @param xml */ XML setChildren(Object xml) { if (length() == 1) { return getXmlFromAnnotation(0).setChildren(xml); } else { throw ScriptRuntime.typeError("The setChildren method works only on lists containing one item"); } } /** * * @param name */ void setLocalName(String localName) { if (length() == 1) { getXmlFromAnnotation(0).setLocalName(localName); } else { throw ScriptRuntime.typeError("The setLocalName method works only on lists containing one item"); } } /** * * @param name */ void setName(QName qname) { if (length() == 1) { getXmlFromAnnotation(0).setName(qname); } else { throw ScriptRuntime.typeError("The setName method works only on lists containing one item"); } } /** * * @param ns */ void setNamespace(Namespace ns) { if (length() == 1) { getXmlFromAnnotation(0).setNamespace(ns); } else { throw ScriptRuntime.typeError("The setNamespace method works only on lists containing one item"); } } /** * * * @return */ XMLList text() { XMLList result = new XMLList(lib); for (int i = 0; i < length(); i++) { result.addToList(getXmlFromAnnotation(i).text()); } return result; } /** * * @return */ public String toString() { if (hasSimpleContent()) { StringBuffer sb = new StringBuffer(); for(int i = 0; i < length(); i++) { XML next = getXmlFromAnnotation(i); sb.append(next.toString()); } return sb.toString(); } else { return toXMLString(0); } } String toSource(int indent) { // XXX indent is ignored return "<>"+toXMLString(0)+""; } /** * * @return */ String toXMLString(int indent) { StringBuffer sb = new StringBuffer(); for(int i = 0; i < length(); i++) { if (i > 0) { sb.append('\n'); } sb.append(getXmlFromAnnotation(i).toXMLString(indent)); } return sb.toString(); } /** * * @return */ Object valueOf() { return this; } // // Other public Functions from XMLObject // /** * * @param target * @return */ boolean equivalentXml(Object target) { boolean result = false; // Zero length list should equate to undefined if (target instanceof Undefined && length() == 0) { result = true; } else if (length() == 1) { result = getXmlFromAnnotation(0).equivalentXml(target); } else if (target instanceof XMLList) { XMLList otherList = (XMLList) target; if (otherList.length() == length()) { result = true; for (int i = 0; i < length(); i++) { if (!getXmlFromAnnotation(i).equivalentXml(otherList.getXmlFromAnnotation(i))) { result = false; break; } } } } return result; } /** * * @param name * @param start * @return */ private XMLList getPropertyList(XMLName name) { XMLList propertyList = new XMLList(lib); javax.xml.namespace.QName qname = null; if (!name.isDescendants() && !name.isAttributeName()) { // Only set the targetProperty if this is a regular child get // and not a descendant or attribute get qname = new javax.xml.namespace.QName(name.uri(), name.localName()); } propertyList.setTargets(this, qname); for (int i = 0; i < length(); i++) { propertyList.addToList( getXmlFromAnnotation(i).getPropertyList(name)); } return propertyList; } private Object applyOrCall(boolean isApply, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { String methodName = isApply ? "apply" : "call"; if(!(thisObj instanceof XMLList) || ((XMLList)thisObj).targetProperty == null) throw ScriptRuntime.typeError1("msg.isnt.function", methodName); return ScriptRuntime.applyOrCall(isApply, cx, scope, thisObj, args); } protected Object jsConstructor(Context cx, boolean inNewExpr, Object[] args) { if (args.length == 0) { return new XMLList(lib); } else { Object arg0 = args[0]; if (!inNewExpr && arg0 instanceof XMLList) { // XMLList(XMLList) returns the same object. return arg0; } return new XMLList(lib, arg0); } } org.apache.xmlbeans.XmlObject getXmlObject() { if (length() == 1) { return getXmlFromAnnotation(0).getXmlObject(); } else { throw ScriptRuntime.typeError("getXmlObject method works only on lists containing one item"); } } /** * See ECMA 357, 11_2_2_1, Semantics, 3_e. */ public Scriptable getExtraMethodSource(Context cx) { if (length() == 1) { return getXmlFromAnnotation(0); } return null; } public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { // This XMLList is being called as a Function. // Let's find the real Function object. if(targetProperty == null) throw ScriptRuntime.notFunctionError(this); String methodName = targetProperty.getLocalPart(); boolean isApply = methodName.equals("apply"); if(isApply || methodName.equals("call")) return applyOrCall(isApply, cx, scope, thisObj, args); Callable method = ScriptRuntime.getElemFunctionAndThis( this, methodName, cx); // Call lastStoredScriptable to clear stored thisObj // but ignore the result as the method should use the supplied // thisObj, not one from redirected call ScriptRuntime.lastStoredScriptable(cx); return method.call(cx, scope, thisObj, args); } public Scriptable construct(Context cx, Scriptable scope, Object[] args) { throw ScriptRuntime.typeError1("msg.not.ctor", "XMLList"); } }