/*
* 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.ode.bpel.compiler.bom;
import org.apache.ode.bpel.compiler.api.SourceLocation;
import org.apache.ode.utils.DOMUtils;
import org.apache.ode.utils.NSContext;
import org.apache.ode.utils.stl.CollectionsX;
import org.apache.ode.utils.stl.MemberOfFunction;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.namespace.QName;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Common interface to all BPEL object model (BOM) objects. Provides for
* location information (i.e. line numbers) and namespace context (XML namespace
* prefix maps).
*/
public class BpelObject implements SourceLocation {
public static final QName ATTR_LINENO = new QName("urn:org.apache.ode.bpel.compiler", "lineno");
private final Element _element;
private final QName _type;
private final NSContext _nsContext;
private List<BpelObject> _children = null;
/** URI of the source document. */
private URI _docURI;
public BpelObject(Element el) {
_element = el;
_type = new QName(el.getNamespaceURI(), el.getLocalName());
_nsContext = new NSContext();
initNSContext(el);
}
public QName getType() {
return _type;
}
public Element getElement() {
return _element;
}
/**
* Get the line number in the BPEL source document where this object is
* defined.
*
* @return line number
*/
public int getLineNo() {
return Integer.valueOf(getAttribute(ATTR_LINENO, "-1"));
}
/**
* Get the namespace context for this BPEL object (i.e. prefix-to-namespace
* mapping).
*
* @return namespace context
*/
public NSContext getNamespaceContext() {
return _nsContext;
}
/**
* Return the declared extensibility elements. The extensibility elements
* declared as subelements of this BpelObject will be returned with a value
* type of org.w3c.dom.Element. The ones declared as extensibility
* attributes will be returned as a value type of String.
*
* @return extensibility qualified names and the full elements value (String
* or Element)
*/
public Map<QName, Object> getExtensibilityElements() {
// We consider anything that is not in the namespace of this element to be an
// extensibility element/attribute.
HashMap<QName, Object> ee = new HashMap<QName,Object>();
for (BpelObject child :getChildren()) {
if (child.getType().getNamespaceURI() != null && !child.getType().getNamespaceURI().equals(getType().getNamespaceURI()))
ee.put(child.getType(), child.getElement());
}
NamedNodeMap nnm = getElement().getAttributes();
for (int i = 0; i < nnm.getLength(); ++i) {
Node n = nnm.item(i);
if (n.getNamespaceURI() != null && !n.getNamespaceURI().equals(getType().getNamespaceURI()))
ee.put(new QName(n.getNamespaceURI(), n.getLocalName()), n.getTextContent());
}
return ee;
}
public Element getExtensibilityElement(QName extElName) {
BpelObject e = getFirstChild(extElName);
if (e == null)
return null;
return e.getElement();
}
public Element getFirstExtensibilityElementElement() {
Element child = null;
NodeList nl = getElement().getChildNodes();
for (int i = 0; i < nl.getLength(); ++i) {
Node node = nl.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE &&
!getType().getNamespaceURI().equals(node.getNamespaceURI())) {
child = (Element)node;
break;
}
}
return child;
}
/**
* Is this a BPEL 1.1 object?
* @return
*/
public boolean is11() {
return getType().getNamespaceURI() != null &&
(getType().getNamespaceURI().equals(Bpel11QNames.NS_BPEL4WS_2003_03)
|| getType().getNamespaceURI().equals(Bpel11QNames.NS_BPEL4WS_PARTNERLINK_2003_05));
}
public boolean is20Draft() {
return getType().getNamespaceURI() != null &&
(getType().getNamespaceURI().equals(Bpel20QNames.NS_WSBPEL2_0)
|| getType().getNamespaceURI().equals(Bpel20QNames.NS_WSBPEL_PARTNERLINK_2004_03));
}
protected boolean isAttributeSet(String attrname) {
return null != getAttribute(attrname, null);
}
protected <T extends BpelObject> List<T> getChildren(Class<T> cls) {
return CollectionsX.filter(new ArrayList<T>(), getChildren(), cls);
}
protected <T extends BpelObject> T getFirstChild(Class<T> cls) {
List<T> children = getChildren(cls);
if (children.size() == 0)
return null;
return children.get(0);
}
protected List<BpelObject> getChildren(final QName type) {
return CollectionsX.filter(new ArrayList<BpelObject>(), getChildren(), new MemberOfFunction<BpelObject>() {
@Override
public boolean isMember(BpelObject o) {
return o.getType().equals(type);
}
});
}
protected BpelObject getFirstChild(final QName type) {
return CollectionsX.find_if(getChildren(), new MemberOfFunction<BpelObject>() {
@Override
public boolean isMember(BpelObject o) {
return o.getType().equals(type);
}
});
}
protected QName rewriteTargetNS(QName target) {
return new QName(getType().getNamespaceURI(), target.getLocalPart());
}
protected List<BpelObject> getChildren() {
if (_children == null) {
_children = new ArrayList<BpelObject>();
NodeList nl = _element.getChildNodes();
for (int i = 0; i < nl.getLength(); ++i) {
Node node = nl.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE)
_children.add(createBpelObject((Element) node));
}
}
return _children;
}
protected BpelObject createBpelObject(Element element) {
return BpelObjectFactory.getInstance().createBpelObject(element,_docURI);
}
protected String getAttribute(QName name, String dflt) {
String val = _element.getAttributeNS(name.getNamespaceURI(), name.getLocalPart());
if (val == null || "".equals(val))
return dflt;
return val;
}
protected String getAttribute(String name, String dflt) {
String val = _element.getAttribute(name);
if (val == null || "".equals(val))
return dflt;
return val;
}
protected String getAttribute(String name) {
return getAttribute(name, null);
}
protected <T> T getAttribute(String attrName, Map<String, T> suppressJoinFailure, T notset) {
String val = getAttribute(attrName, null);
if (val == null || "".equals(val))
return notset;
return suppressJoinFailure.get(val);
}
/**
* Initialize object's namespace context (recursively).
*
* @param el
* object's associated element.
*/
private void initNSContext(Element el) {
if (el.getParentNode() != null && el.getParentNode().getNodeType() == Node.ELEMENT_NODE)
initNSContext((Element) el.getParentNode());
NamedNodeMap attrs = el.getAttributes();
for (int i = 0; i < attrs.getLength(); ++i) {
Attr attr = (Attr) attrs.item(i);
if (!attr.getName().startsWith("xmlns:"))
continue;
String prefix = attr.getLocalName();
String uri = attr.getValue();
_nsContext.register(prefix, uri);
}
Attr dflt = el.getAttributeNode("xmlns");
if (dflt != null) {
_nsContext.register("", dflt.getTextContent());
}
}
public String getTextValue() {
getElement().normalize();
for (Node n = getElement().getFirstChild(); n != null; n = n.getNextSibling())
switch (n.getNodeType()) {
case Node.TEXT_NODE:
case Node.ELEMENT_NODE:
case Node.CDATA_SECTION_NODE:
return n.getNodeValue();
}
return null;
}
@Override
public String toString() {
return DOMUtils.domToString(_element);
}
public int getColumnNo() {
return 0;
}
public String getPath() {
return null;
}
public URI getURI() {
return _docURI;
}
public void setURI(URI uri) {
_docURI = uri;
}
}