blob: f26e07de9e51bf609ad76f0ed536954b7ae90e98 [file] [log] [blame]
/*
* Copyright 2004,2005 The Apache Software Foundation.
*
* Licensed 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.axiom.om.impl.llom;
import org.apache.axiom.om.*;
import org.apache.axiom.om.impl.OMContainerEx;
import org.apache.axiom.om.impl.OMNamespaceImpl;
import org.apache.axiom.om.impl.OMNodeEx;
import org.apache.axiom.om.impl.builder.StAXOMBuilder;
import org.apache.axiom.om.impl.llom.factory.OMLinkedListImplFactory;
import org.apache.axiom.om.impl.traverse.OMChildElementIterator;
import org.apache.axiom.om.impl.traverse.OMChildrenIterator;
import org.apache.axiom.om.impl.traverse.OMChildrenQNameIterator;
import org.apache.axiom.om.impl.util.EmptyIterator;
import org.apache.axiom.om.impl.util.OMSerializerUtil;
import org.apache.axiom.om.util.ElementHelper;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import java.io.ByteArrayOutputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
/**
* Class OMElementImpl
*/
public class OMElementImpl extends OMNodeImpl
implements OMElement, OMConstants, OMContainerEx {
public static final OMNamespace DEFAULT_DEFAULT_NS_OBJECT = new OMNamespaceImpl("", "");
/**
* Field ns
*/
protected OMNamespace ns;
/**
* Field localName
*/
protected String localName;
/**
* Field firstChild
*/
protected OMNode firstChild;
/**
* Field namespaces
*/
protected HashMap namespaces = null;
/**
* Field attributes
*/
protected HashMap attributes = null;
/**
* Field noPrefixNamespaceCounter
*/
protected int noPrefixNamespaceCounter = 0;
protected OMNode lastChild;
private int lineNumber;
private static final EmptyIterator EMPTY_ITERATOR = new EmptyIterator();
/**
* Constructor OMElementImpl.
* A null namespace indicates that the default namespace in scope is used
*/
public OMElementImpl(String localName, OMNamespace ns, OMContainer parent,
OMXMLParserWrapper builder, OMFactory factory) {
super(parent, factory, false);
this.localName = localName;
if (ns != null) {
setNamespace(ns);
}
this.builder = builder;
firstChild = null;
}
/**
* Constructor OMElementImpl.
*/
public OMElementImpl(String localName, OMNamespace ns, OMFactory factory) {
this(localName, ns, null, factory);
}
/**
* This is the basic constructor for OMElement. All the other constructors
* depends on this.
*
* @param localName - this MUST always be not null
* @param ns - can be null
* @param parent - this should be an OMContainer
* @param factory - factory that created this OMElement
* <p/>
* A null namespace indicates that the default namespace in scope is used
*/
public OMElementImpl(String localName, OMNamespace ns, OMContainer parent,
OMFactory factory) {
super(parent, factory, true);
if (localName == null || localName.trim().length() == 0) {
throw new OMException("localname can not be null or empty");
}
this.localName = localName;
if (ns != null) {
setNamespace(ns);
}
}
/**
* It is assumed that the QName passed contains, at least, the localName for this element.
*
* @param qname - this should be valid qname according to javax.xml.namespace.QName
* @throws OMException
*/
public OMElementImpl(QName qname, OMContainer parent, OMFactory factory)
throws OMException {
this(qname.getLocalPart(), null, parent, factory);
this.ns = handleNamespace(qname);
}
/**
* Method handleNamespace.
*/
OMNamespace handleNamespace(QName qname) {
OMNamespace ns = null;
// first try to find a namespace from the scope
String namespaceURI = qname.getNamespaceURI();
if (namespaceURI != null && namespaceURI.length() > 0) {
ns = findNamespace(qname.getNamespaceURI(),
qname.getPrefix());
/**
* What is left now is
* 1. nsURI = null & parent != null, but ns = null
* 2. nsURI != null, (parent doesn't have an ns with given URI), but ns = null
*/
if (ns == null) {
String prefix = qname.getPrefix();
if ("".equals(prefix)) {
prefix = OMSerializerUtil.getNextNSPrefix();
}
ns = declareNamespace(namespaceURI, prefix);
}
if (ns != null) {
this.ns = ns;
}
}
return ns;
}
/**
* Method handleNamespace.
*
* @return Returns namespace.
*/
private OMNamespace handleNamespace(OMNamespace ns) {
OMNamespace namespace = findNamespace(ns.getNamespaceURI(),
ns.getPrefix());
if (namespace == null) {
namespace = declareNamespace(ns);
}
return namespace;
}
/**
* Adds child to the element. One can decide whether to append the child or to add to the
* front of the children list.
*/
public void addChild(OMNode child) {
if (child.getOMFactory() instanceof OMLinkedListImplFactory) {
addChild((OMNodeImpl) child);
} else {
addChild(importNode(child));
}
}
/**
* Searches for children with a given QName and returns an iterator to traverse through
* the OMNodes.
* This QName can contain any combination of prefix, localname and URI.
*
* @throws OMException
*/
public Iterator getChildrenWithName(QName elementQName) {
return new OMChildrenQNameIterator(getFirstOMChild(),
elementQName);
}
/**
* Method getFirstChildWithName.
*
* @throws OMException
*/
public OMElement getFirstChildWithName(QName elementQName) throws OMException {
OMChildrenQNameIterator omChildrenQNameIterator =
new OMChildrenQNameIterator(getFirstOMChild(),
elementQName);
OMNode omNode = null;
if (omChildrenQNameIterator.hasNext()) {
omNode = (OMNode) omChildrenQNameIterator.next();
}
return ((omNode != null) && (OMNode.ELEMENT_NODE == omNode.getType())) ?
(OMElement) omNode : null;
}
/**
* Method addChild.
*/
private void addChild(OMNodeImpl child) {
//the order of these statements is VERY important
//Since setting the parent has a detach method inside
//it strips down all the rerefences to siblings.
//setting the siblings should take place AFTER setting the parent
child.setParent(this);
if (firstChild == null) {
firstChild = child;
child.previousSibling = null;
} else {
child.previousSibling = (OMNodeImpl) lastChild;
((OMNodeImpl) lastChild).nextSibling = child;
}
child.nextSibling = null;
lastChild = child;
if (!child.isComplete()) {
this.setComplete(false);
}
}
/**
* Gets the next sibling. This can be an OMAttribute or OMText or
* OMELement for others.
*
* @throws OMException
*/
public OMNode getNextOMSibling() throws OMException {
while (!done && builder != null) {
int token = builder.next();
if (token == XMLStreamConstants.END_DOCUMENT) {
throw new OMException("Parser has already reached end of the document. No siblings found");
}
}
return super.getNextOMSibling();
}
/**
* Returns a collection of this element. Children can be of types OMElement, OMText.
*
* @return Returns children.
*/
public Iterator getChildren() {
return new OMChildrenIterator(getFirstOMChild());
}
/**
* Returns a filtered list of children - just the elements.
*
* @return Returns an iterator of the child elements.
*/
public Iterator getChildElements() {
return new OMChildElementIterator(getFirstElement());
}
/**
* Creates a namespace in the current element scope.
*
* @return Returns namespace.
*/
public OMNamespace declareNamespace(String uri, String prefix) {
if ("".equals(prefix))
prefix = OMSerializerUtil.getNextNSPrefix();
OMNamespaceImpl ns = new OMNamespaceImpl(uri, prefix);
return declareNamespace(ns);
}
/**
* We use "" to store the default namespace of this element. As one can see user can not give ""
* as the prefix, when he declare a usual namespace.
*
* @param uri
*/
public OMNamespace declareDefaultNamespace(String uri) {
OMNamespaceImpl namespace = new OMNamespaceImpl(uri == null ? "" : uri, "");
if (namespaces == null) {
this.namespaces = new HashMap(5);
}
namespaces.put("", namespace);
return namespace;
}
public OMNamespace getDefaultNamespace() {
OMNamespace defaultNS;
if (namespaces != null && (defaultNS = (OMNamespace) namespaces.get("")) != null) {
return defaultNS;
}
if (parent instanceof OMElementImpl) {
return ((OMElementImpl) parent).getDefaultNamespace();
}
return null;
}
/**
* @return Returns namespace.
*/
public OMNamespace declareNamespace(OMNamespace namespace) {
if (namespaces == null) {
this.namespaces = new HashMap(5);
}
String prefix = namespace.getPrefix();
if (prefix == null) {
prefix = OMSerializerUtil.getNextNSPrefix();
namespace = new OMNamespaceImpl(namespace.getNamespaceURI(), prefix);
}
namespaces.put(prefix, namespace);
return namespace;
}
/**
* Finds a namespace with the given uri and prefix, in the scope of the document.
* Starts to find from the current element and goes up in the hiararchy until one is found.
* If none is found, returns null.
*/
public OMNamespace findNamespace(String uri, String prefix) {
// check in the current element
OMNamespace namespace = findDeclaredNamespace(uri, prefix);
if (namespace != null) {
return namespace;
}
// go up to check with ancestors
if (parent != null) {
//For the OMDocumentImpl there won't be any explicit namespace
//declarations, so going up the parent chain till the document
//element should be enough.
if (parent instanceof OMElement) {
namespace = ((OMElementImpl) parent).findNamespace(uri, prefix);
}
}
return namespace;
}
public OMNamespace findNamespaceURI(String prefix) {
OMNamespace ns = this.namespaces == null ?
null :
(OMNamespace) this.namespaces.get(prefix);
if (ns == null && this.parent instanceof OMElement) {
// try with the parent
ns = ((OMElement) this.parent).findNamespaceURI(prefix);
}
return ns;
}
// Constant
static final OMNamespaceImpl xmlns =
new OMNamespaceImpl(OMConstants.XMLNS_URI,
OMConstants.XMLNS_PREFIX);
/**
* Checks for the namespace <B>only</B> in the current Element.
* This is also used to retrieve the prefix of a known namespace URI.
*/
private OMNamespace findDeclaredNamespace(String uri, String prefix) {
if (uri == null) {
return null;
}
//If the prefix is available and uri is available and its the xml namespace
if (prefix != null && prefix.equals(OMConstants.XMLNS_PREFIX) && uri.equals(OMConstants.XMLNS_URI)) {
return xmlns;
}
if (namespaces == null) {
return null;
}
if (prefix == null || "".equals(prefix)) {
OMNamespace defaultNamespace = this.getDefaultNamespace();
if (defaultNamespace != null && uri.equals(defaultNamespace.getNamespaceURI())) {
return defaultNamespace;
}
Iterator namespaceListIterator = namespaces.values().iterator();
String nsUri;
while (namespaceListIterator.hasNext()) {
OMNamespace omNamespace =
(OMNamespace) namespaceListIterator.next();
nsUri = omNamespace.getNamespaceURI();
if (nsUri != null &&
nsUri.equals(uri)) {
return omNamespace;
}
}
} else {
OMNamespace namespace = (OMNamespace) namespaces.get(prefix);
if (namespace != null && uri.equalsIgnoreCase(namespace.getNamespaceURI())) {
return namespace;
}
}
return null;
}
/**
* Method getAllDeclaredNamespaces.
*
* @return Returns Iterator.
*/
public Iterator getAllDeclaredNamespaces() {
if (namespaces == null) {
return EMPTY_ITERATOR;
}
return namespaces.values().iterator();
}
/**
* Returns a List of OMAttributes.
*
* @return Returns iterator.
*/
public Iterator getAllAttributes() {
if (attributes == null) {
return EMPTY_ITERATOR;
}
return attributes.values().iterator();
}
/**
* Returns a named attribute if present.
*
* @param qname the qualified name to search for
* @return Returns an OMAttribute with the given name if found, or null
*/
public OMAttribute getAttribute(QName qname) {
return attributes == null ? null : (OMAttribute) attributes.get(qname);
}
/**
* Returns a named attribute's value, if present.
*
* @param qname the qualified name to search for
* @return Returns a String containing the attribute value, or null.
*/
public String getAttributeValue(QName qname) {
OMAttribute attr = getAttribute(qname);
return (attr == null) ? null : attr.getAttributeValue();
}
/**
* Inserts an attribute to this element. Implementor can decide as to insert this
* in the front or at the end of set of attributes.
*
* @return Returns attribute.
*/
public OMAttribute addAttribute(OMAttribute attr) {
if (attributes == null) {
this.attributes = new LinkedHashMap(5);
}
OMNamespace namespace = attr.getNamespace();
if (namespace != null && this.findNamespace(namespace.getNamespaceURI(), namespace.getPrefix()) == null) {
this.declareNamespace(namespace.getNamespaceURI(), namespace.getPrefix());
}
attributes.put(attr.getQName(), attr);
return attr;
}
/**
* Method removeAttribute.
*/
public void removeAttribute(OMAttribute attr) {
if (attributes != null) {
attributes.remove(attr.getQName());
}
}
/**
* Method addAttribute.
*
* @return Returns OMAttribute.
*/
public OMAttribute addAttribute(String attributeName, String value,
OMNamespace ns) {
OMNamespace namespace;
if (ns != null) {
namespace = findNamespace(ns.getNamespaceURI(), ns.getPrefix());
if (namespace == null) {
throw new OMException("Given OMNamespace(" + ns.getNamespaceURI() + " " +
ns.getPrefix()
+ ") for "
+
"this attribute is not declared in the scope of this element. First declare the namespace"
+ " and then use it with the attribute");
}
}
return addAttribute(new OMAttributeImpl(attributeName, ns, value, this.factory));
}
/**
* Method setBuilder.
*/
public void setBuilder(OMXMLParserWrapper wrapper) {
this.builder = wrapper;
}
/**
* Method getBuilder.
*
* @return Returns OMXMLParserWrapper.
*/
public OMXMLParserWrapper getBuilder() {
return builder;
}
/**
* Forces the parser to proceed, if parser has not yet finished with the XML input.
*/
public void buildNext() {
if (builder != null) {
builder.next();
}
}
/**
* Method getFirstOMChild.
*
* @return Returns child.
*/
public OMNode getFirstOMChild() {
while ((firstChild == null) && !done) {
buildNext();
}
return firstChild;
}
/**
* Method setFirstChild.
*/
public void setFirstChild(OMNode firstChild) {
if (firstChild != null) {
((OMNodeEx) firstChild).setParent(this);
}
this.firstChild = firstChild;
}
/**
* Removes this information item and its children, from the model completely.
*
* @throws OMException
*/
public OMNode detach() throws OMException {
if (!done) {
build();
}
super.detach();
return this;
}
/**
* Method isComplete.
*
* @return Returns boolean.
*/
public boolean isComplete() {
return done;
}
/**
* Gets the type of node, as this is the super class of all the nodes.
*/
public int getType() {
return OMNode.ELEMENT_NODE;
}
public void build() throws OMException {
/**
* builder is null. Meaning this is a programatical created element but it has children which are not completed
* Build them all.
*/
if (builder == null && !done) {
for (Iterator childrenIterator = this.getChildren(); childrenIterator.hasNext();) {
OMNode omNode = (OMNode) childrenIterator.next();
omNode.build();
}
} else {
super.build();
}
}
/**
* Method getXMLStreamReader.
*
* @see OMElement#getXMLStreamReader()
*/
public XMLStreamReader getXMLStreamReader() {
return getXMLStreamReader(true);
}
/**
* Method getXMLStreamReaderWithoutCaching.
*
* @see OMElement#getXMLStreamReaderWithoutCaching()
*/
public XMLStreamReader getXMLStreamReaderWithoutCaching() {
return getXMLStreamReader(false);
}
/**
* Method getXMLStreamReader.
*
* @return Returns reader.
*/
private XMLStreamReader getXMLStreamReader(boolean cache) {
if ((builder == null) && !cache) {
throw new UnsupportedOperationException(
"This element was not created in a manner to be switched");
}
if (builder != null && builder.isCompleted() && !cache) {
throw new UnsupportedOperationException(
"The parser is already consumed!");
}
return new OMStAXWrapper(builder, this, cache);
}
/**
* Sets the text of the given element.
* caution - This method will wipe out all the text elements (and hence any
* mixed content) before setting the text.
*/
public void setText(String text) {
OMNode child = this.getFirstOMChild();
while (child != null) {
if (child.getType() == OMNode.TEXT_NODE) {
child.detach();
}
child = child.getNextOMSibling();
}
OMAbstractFactory.getOMFactory().createOMText(this, text);
}
/**
* Sets the text, as a QName, of the given element.
* caution - This method will wipe out all the text elements (and hence any
* mixed content) before setting the text.
*/
public void setText(QName text) {
OMNode child = this.getFirstOMChild();
while (child != null) {
if (child.getType() == OMNode.TEXT_NODE) {
child.detach();
}
child = child.getNextOMSibling();
}
OMAbstractFactory.getOMFactory().createOMText(this, text);
}
/**
* Selects all the text children and concatinates them to a single string.
*
* @return Returns String.
*/
public String getText() {
String childText = "";
OMNode child = this.getFirstOMChild();
OMText textNode;
while (child != null) {
if (child.getType() == OMNode.TEXT_NODE) {
textNode = (OMText) child;
if (textNode.getText() != null &&
!"".equals(textNode.getText())) {
childText += textNode.getText();
}
}
child = child.getNextOMSibling();
}
return childText;
}
public QName getTextAsQName() {
String childText = "";
OMNode child = this.getFirstOMChild();
OMText textNode;
while (child != null) {
if (child.getType() == OMNode.TEXT_NODE) {
textNode = (OMText) child;
if (textNode.getText() != null &&
!"".equals(textNode.getText())) {
String namespaceURI = textNode.getTextAsQName().getNamespaceURI();
if (namespaceURI != null && !"".equals(namespaceURI)) {
return textNode.getTextAsQName();
}
childText += textNode.getText();
}
}
child = child.getNextOMSibling();
}
return new QName(childText);
}
/**
* Returns the concatination string of TRIMMED values of all
* OMText child nodes of this element.
* This is included purely to improve usability.
*/
public String getTrimmedText() {
String childText = "";
OMNode child = this.getFirstOMChild();
OMText textNode;
while (child != null) {
if (child.getType() == OMNode.TEXT_NODE) {
textNode = (OMText) child;
if (textNode.getText() != null &&
!"".equals(textNode.getText().trim())) {
childText += textNode.getText().trim();
}
}
child = child.getNextOMSibling();
}
return childText;
}
/**
* Method internalSerialize.
*
* @throws XMLStreamException
*/
public void internalSerialize(XMLStreamWriter writer) throws XMLStreamException {
internalSerialize(writer, true);
}
///////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
protected void internalSerialize(XMLStreamWriter writer, boolean cache) throws XMLStreamException {
if (cache) {
//in this case we don't care whether the elements are built or not
//we just call the serializeAndConsume methods
OMSerializerUtil.serializeStartpart(this, writer);
//serialize children
Iterator children = this.getChildren();
while (children.hasNext()) {
((OMNodeEx) children.next()).internalSerialize(writer);
}
OMSerializerUtil.serializeEndpart(writer);
} else {
//Now the caching is supposed to be off. However caching been switched off
//has nothing to do if the element is already built!
if (this.done || (this.builder == null)) {
OMSerializerUtil.serializeStartpart(this, writer);
OMNodeImpl child = (OMNodeImpl) firstChild;
while (child != null) {
if ((!(child instanceof OMElement)) || child.isComplete() || child.builder == null) {
child.internalSerializeAndConsume(writer);
} else {
OMElement element = (OMElement) child;
element.getBuilder().setCache(false);
OMSerializerUtil.serializeByPullStream(element, writer, cache);
}
child = child.nextSibling;
}
OMSerializerUtil.serializeEndpart(writer);
} else {
OMSerializerUtil.serializeByPullStream(this, writer, cache);
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
/**
* This method serializes and consumes without building the object structure in memory.
* Misuse of this method will cause loss of data. So it is advised to use
* populateYourSelf() method, before calling this method, if one wants to
* preserve data in the stream. This was requested during the second Axis2 summit.
*
* @throws XMLStreamException
*/
public void internalSerializeAndConsume(XMLStreamWriter writer) throws XMLStreamException {
this.internalSerialize(writer, false);
}
/**
* Gets first element.
*
* @return Returns element.
*/
public OMElement getFirstElement() {
OMNode node = getFirstOMChild();
while (node != null) {
if (node.getType() == OMNode.ELEMENT_NODE) {
return (OMElement) node;
} else {
node = node.getNextOMSibling();
}
}
return null;
}
/**
* Method getLocalName.
*
* @return Returns local name.
*/
public String getLocalName() {
return localName;
}
/**
* Method setLocalName.
*/
public void setLocalName(String localName) {
this.localName = localName;
}
/**
* Method getNamespace.
*
* @throws OMException
*/
public OMNamespace getNamespace() throws OMException {
// return ns != null ? ns : DEFAULT_DEFAULT_NS_OBJECT;
if (ns == null) {
// User wants to keep this element in the default default namespace. Let's try to see the default namespace
// is overriden by some one up in the tree
OMNamespace parentDefaultNS = this.findNamespaceURI("");
if(parentDefaultNS != null && !"".equals(parentDefaultNS.getNamespaceURI())){
// if it was overriden, then we must explicitly declare default default namespace as the namespace
// of this element
ns = DEFAULT_DEFAULT_NS_OBJECT;
}
}
return ns;
}
/**
* Method setNamespace.
*/
public void setNamespace(OMNamespace namespace) {
OMNamespace nsObject = null;
if (namespace != null) {
nsObject = handleNamespace(namespace);
}
this.ns = nsObject;
}
public void setNamespaceWithNoFindInCurrentScope(OMNamespace namespace) {
this.ns = namespace;
}
/**
* Method getQName.
*
* @return Returns QName.
*/
public QName getQName() {
QName qName;
if (ns != null) {
if (ns.getPrefix() != null) {
qName = new QName(ns.getNamespaceURI(), localName, ns.getPrefix());
} else {
qName = new QName(ns.getNamespaceURI(), localName);
}
} else {
qName = new QName(localName);
}
return qName;
}
public String toStringWithConsume() throws XMLStreamException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
this.serializeAndConsume(baos);
return new String(baos.toByteArray());
}
public String toString() {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
this.serialize(baos);
} catch (XMLStreamException e) {
throw new RuntimeException("Can not serialize OM Element " + this.getLocalName(), e);
}
return new String(baos.toByteArray());
}
/**
* Method discard.
*
* @throws OMException
*/
public void discard() throws OMException {
if (done || builder == null) {
this.detach();
} else {
builder.discard(this);
}
}
/**
* Converts a prefix:local qname string into a proper QName, evaluating it
* in the OMElement context. Unprefixed qnames resolve to the local namespace.
*
* @param qname prefixed qname string to resolve
* @return Returns null for any failure to extract a qname.
*/
public QName resolveQName(String qname) {
ElementHelper helper = new ElementHelper(this);
return helper.resolveQName(qname);
}
public OMElement cloneOMElement() {
OMElement clonedElement = new StAXOMBuilder(this.getXMLStreamReader(true)).getDocumentElement();
clonedElement.build();
return clonedElement;
}
public void setLineNumber(int lineNumber) {
this.lineNumber = lineNumber;
}
public int getLineNumber() {
return lineNumber;
}
/* (non-Javadoc)
* @see org.apache.axiom.om.OMNode#buildAll()
*/
public void buildWithAttachments() {
if (!done) {
this.build();
}
Iterator iterator = getChildren();
while (iterator.hasNext()) {
OMNode node = (OMNode) iterator.next();
node.buildWithAttachments();
}
}
/**
* This method will be called when one of the children becomes complete.
*/
protected void notifyChildComplete() {
if (!this.done && builder == null) {
Iterator iterator = getChildren();
while (iterator.hasNext()) {
OMNode node = (OMNode) iterator.next();
if (!node.isComplete()) {
return;
}
}
this.setComplete(true);
}
}
}