/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.cxf.javascript;
import java.lang.reflect.InvocationTargetException;
import org.w3c.dom.Attr;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
/**
* A Rhino wrapper around org.w3c.dom.Node. Not comprehensive, but enough to test CXF JavaScript.
*/
public class JsSimpleDomNode extends ScriptableObject {
private Node wrappedNode;
private boolean childrenWrapped;
private boolean attributesWrapped;
private JsSimpleDomNode previousSibling;
private JsSimpleDomNode nextSibling;
private JsSimpleDomNode[] children;
private JsNamedNodeMap attributes;
/**
* Only exists to make Rhino happy. Should never be used.
*/
public JsSimpleDomNode() {
}
public static void register(ScriptableObject scope) {
try {
ScriptableObject.defineClass(scope, JsSimpleDomNode.class);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
@Override
public String getClassName() {
return "Node";
}
public Node getWrappedNode() {
return wrappedNode;
}
//CHECKSTYLE:OFF
public String jsGet_localName() {
return wrappedNode.getLocalName();
}
public String jsGet_namespaceURI() {
return wrappedNode.getNamespaceURI();
}
public Object jsGet_firstChild() {
establishChildren();
if (children.length > 0)
return children[0];
else
return null;
}
public Object jsGet_nextSibling() {
return nextSibling;
}
public Object jsGet_previousSibling() {
return previousSibling;
}
public Object jsGet_parentNode() {
// risk errors in object equality ...
return wrapNode(this, wrappedNode.getParentNode());
}
public int jsGet_nodeType() {
return wrappedNode.getNodeType();
}
public String jsGet_nodeValue() {
return wrappedNode.getNodeValue();
}
public String jsGet_nodeName() {
return wrappedNode.getNodeName();
}
// in a more complete version of this, we'd use a different object type to wrap documents.
public Object jsGet_documentElement() {
if(9 /* Document */ != wrappedNode.getNodeType()) {
return null;
} else {
establishChildren();
return children[0]; // it is, after all, just a convenience feature.
}
}
public Object[] jsGet_childNodes() {
establishChildren();
return children;
}
public Object jsGet_attributes() {
establishAttributes();
return attributes;
}
public String jsFunction_getAttributeNS(String namespaceURI, String localName) {
NamedNodeMap attributes = wrappedNode.getAttributes();
Node attrNode = attributes.getNamedItemNS(namespaceURI, localName);
if(attrNode == null) {
return null;
} else {
Attr attribute = (Attr) attrNode;
return attribute.getValue();
}
}
public String jsFunction_getAttribute(String localName) {
NamedNodeMap attributes = wrappedNode.getAttributes();
Node attrNode = attributes.getNamedItem(localName);
if(attrNode == null) {
return null;
} else {
Attr attribute = (Attr) attrNode;
return attribute.getValue();
}
}
//CHECKSTYLE:ON
public static JsSimpleDomNode wrapNode(Scriptable scope, Node node) {
if (node == null) {
return null;
}
Context cx = Context.enter();
JsSimpleDomNode newObject = (JsSimpleDomNode)cx.newObject(scope, "Node");
newObject.initialize(node, null);
return newObject;
}
private JsSimpleDomNode newObject(Node node, JsSimpleDomNode prev) {
Context cx = Context.enter();
JsSimpleDomNode newObject = (JsSimpleDomNode)cx.newObject(getParentScope(), "Node");
newObject.initialize(node, prev);
return newObject;
}
private void establishChildren() {
if (!childrenWrapped) {
if (wrappedNode.hasChildNodes()) {
children = new JsSimpleDomNode[wrappedNode.getChildNodes().getLength()];
Node node = wrappedNode.getFirstChild();
int x = 0;
while (node != null) {
JsSimpleDomNode prev = null;
if (x > 0) {
prev = (JsSimpleDomNode)children[x - 1];
}
children[x] = newObject(node, prev);
if (x > 0) {
children[x - 1].setNext(children[x]);
}
node = node.getNextSibling();
x++;
}
} else {
children = new JsSimpleDomNode[0];
}
childrenWrapped = true;
}
}
private void establishAttributes() {
if (!attributesWrapped) {
NamedNodeMap nodeAttributes = wrappedNode.getAttributes();
attributes = JsNamedNodeMap.wrapMap(getParentScope(), nodeAttributes);
attributesWrapped = true;
}
}
//rhino won't let us use a constructor.
void initialize(Node node, JsSimpleDomNode prev) {
wrappedNode = node;
childrenWrapped = false;
previousSibling = prev;
}
void setNext(JsSimpleDomNode next) {
nextSibling = next;
}
}