blob: acdd4bb3375e8d9c204b863a6751b55259a879ac [file] [log] [blame]
/* Copyright 2004 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.xmlbeans.impl.store;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlDocumentProperties;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlOptions;
import org.apache.xmlbeans.impl.common.GlobalLock;
import org.apache.xmlbeans.impl.common.XMLChar;
import org.apache.xmlbeans.impl.store.Locale.ChangeListener;
import org.apache.xmlbeans.impl.store.Path.PathEngine;
import org.apache.xmlbeans.impl.store.Saver.TextSaver;
import org.apache.xmlbeans.xml.stream.XMLInputStream;
import org.w3c.dom.Node;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.ext.LexicalHandler;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamReader;
import java.io.*;
import java.util.Collection;
import java.util.Map;
import java.util.function.Supplier;
public final class Cursor implements XmlCursor, ChangeListener {
static final int ROOT = Cur.ROOT;
static final int ELEM = Cur.ELEM;
static final int ATTR = Cur.ATTR;
static final int COMMENT = Cur.COMMENT;
static final int PROCINST = Cur.PROCINST;
static final int TEXT = Cur.TEXT;
private Cur _cur;
private PathEngine _pathEngine;
private int _currentSelection;
private ChangeListener _nextChangeListener;
Cursor(Xobj x, int p) {
_cur = x._locale.weakCur(this);
_cur.moveTo(x, p);
_currentSelection = -1;
}
Cursor(Cur c) {
this(c._xobj, c._pos);
}
private static boolean isValid(Cur c) {
if (c.kind() <= 0) {
c.push();
if (c.toParentRaw()) {
int pk = c.kind();
if (pk == COMMENT || pk == PROCINST || pk == ATTR) {
return false;
}
}
c.pop();
}
return true;
}
private boolean isValid() {
return isValid(_cur);
}
Locale locale() {
return _cur._locale;
}
Cur tempCur() {
return _cur.tempCur();
}
public void dump(PrintStream o) {
_cur.dump(o);
}
static void validateLocalName(QName name) {
if (name == null) {
throw new IllegalArgumentException("QName is null");
}
validateLocalName(name.getLocalPart());
}
static void validateLocalName(String name) {
if (name == null) {
throw new IllegalArgumentException("Name is null");
}
if (name.length() == 0) {
throw new IllegalArgumentException("Name is empty");
}
if (!XMLChar.isValidNCName(name)) {
throw new IllegalArgumentException("Name is not valid");
}
}
static void validatePrefix(String name) {
if (name == null) {
throw new IllegalArgumentException("Prefix is null");
}
if (name.length() == 0) {
throw new IllegalArgumentException("Prefix is empty");
}
if (Locale.beginsWithXml(name)) {
throw new IllegalArgumentException("Prefix begins with 'xml'");
}
if (!XMLChar.isValidNCName(name)) {
throw new IllegalArgumentException("Prefix is not valid");
}
}
private static void complain(String msg) {
throw new IllegalArgumentException(msg);
}
private void checkInsertionValidity(Cur that) {
int thatKind = that.kind();
if (thatKind < 0) {
complain("Can't move/copy/insert an end token.");
}
if (thatKind == ROOT) {
complain("Can't move/copy/insert a whole document.");
}
int thisKind = _cur.kind();
if (thisKind == ROOT) {
complain("Can't insert before the start of the document.");
}
if (thatKind == ATTR) {
_cur.push();
_cur.prevWithAttrs();
int pk = _cur.kind();
_cur.pop();
if (pk != ELEM && pk != ROOT && pk != -ATTR) {
complain("Can only insert attributes before other attributes or after containers.");
}
}
if (thisKind == ATTR && thatKind != ATTR) {
complain("Can only insert attributes before other attributes or after containers.");
}
}
private void insertNode(Cur that, String text) {
assert !that.isRoot();
assert that.isNode();
assert isValid(that);
assert isValid();
if (text != null && text.length() > 0) {
that.next();
that.insertString(text);
that.toParent();
}
checkInsertionValidity(that);
that.moveNode(_cur);
_cur.toEnd();
_cur.nextWithAttrs();
}
//
//
//
// TODO - deal with cursors moving to other documents upon release?
// Can I move the ref from one q to another? If not I will have to
// change from a phantom ref to a soft/weak ref so I can know what
// to do when I dequeue from the old q.
public void _dispose() {
_cur.release();
_cur = null;
}
public XmlCursor _newCursor() {
return new Cursor(_cur);
}
public QName _getName() {
// TODO - consider taking this out of the gateway
switch (_cur.kind()) {
case ATTR:
if (_cur.isXmlns()) {
return
_cur._locale.makeQNameNoCheck(_cur.getXmlnsUri(), _cur.getXmlnsPrefix());
}
// Fall thru
case ELEM:
case PROCINST:
return _cur.getName();
}
return null;
}
public void _setName(QName name) {
if (name == null) {
throw new IllegalArgumentException("Name is null");
}
switch (_cur.kind()) {
case ELEM:
case ATTR: {
validateLocalName(name.getLocalPart());
break;
}
case PROCINST: {
validatePrefix(name.getLocalPart());
if (name.getNamespaceURI().length() > 0) {
throw new IllegalArgumentException("Procinst name must have no URI");
}
if (name.getPrefix().length() > 0) {
throw new IllegalArgumentException("Procinst name must have no prefix");
}
break;
}
default:
throw
new IllegalStateException("Can set name on element, atrtribute and procinst only");
}
_cur.setName(name);
}
public TokenType _currentTokenType() {
assert isValid();
switch (_cur.kind()) {
case ROOT:
return TokenType.STARTDOC;
case -ROOT:
return TokenType.ENDDOC;
case ELEM:
return TokenType.START;
case -ELEM:
return TokenType.END;
case TEXT:
return TokenType.TEXT;
case ATTR:
return _cur.isXmlns() ? TokenType.NAMESPACE : TokenType.ATTR;
case COMMENT:
return TokenType.COMMENT;
case PROCINST:
return TokenType.PROCINST;
default:
throw new IllegalStateException();
}
}
public boolean _isStartdoc() {
//return _currentTokenType().isStartdoc();
assert isValid();
return _cur.isRoot();
}
public boolean _isEnddoc() {
//return _currentTokenType().isEnddoc();
assert isValid();
return _cur.isEndRoot();
}
public boolean _isStart() {
//return _currentTokenType().isStart();
assert isValid();
return _cur.isElem();
}
public boolean _isEnd() {
//return _currentTokenType().isEnd();
assert isValid();
return _cur.isEnd();
}
public boolean _isText() {
//return _currentTokenType().isText();
assert isValid();
return _cur.isText();
}
public boolean _isAttr() {
//return _currentTokenType().isAttr();
assert isValid();
return _cur.isNormalAttr();
}
public boolean _isNamespace() {
//return _currentTokenType().isNamespace();
assert isValid();
return _cur.isXmlns();
}
public boolean _isComment() {
//return _currentTokenType().isComment();
assert isValid();
return _cur.isComment();
}
public boolean _isProcinst() {
//return _currentTokenType().isProcinst();
assert isValid();
return _cur.isProcinst();
}
public boolean _isContainer() {
//return _currentTokenType().isContainer();
assert isValid();
return _cur.isContainer();
}
public boolean _isFinish() {
//return _currentTokenType().isFinish();
assert isValid();
return _cur.isFinish();
}
public boolean _isAnyAttr() {
//return _currentTokenType().isAnyAttr();
assert isValid();
return _cur.isAttr();
}
public TokenType _toNextToken() {
assert isValid();
switch (_cur.kind()) {
case ROOT:
case ELEM: {
if (!_cur.toFirstAttr()) {
_cur.next();
}
break;
}
case ATTR: {
if (!_cur.toNextSibling()) {
_cur.toParent();
_cur.next();
}
break;
}
case COMMENT:
case PROCINST: {
_cur.skip();
break;
}
default: {
if (!_cur.next()) {
return TokenType.NONE;
}
break;
}
}
return _currentTokenType();
}
public TokenType _toPrevToken() {
assert isValid();
// This method is different than the Cur version of prev in a few ways. First,
// Cursor iterates over attrs inline with all the other content. Cur will skip attrs, or
// if the Cur in in attrs, it will not jump out of attrs. Also, if moving backwards and
// text is to the left and right, Cur will move to the beginning of that text, while
// Cursor will move further so that the token type to the right is not text.
boolean wasText = _cur.isText();
if (!_cur.prev()) {
assert _cur.isRoot() || _cur.isAttr();
if (_cur.isRoot()) {
return TokenType.NONE;
}
_cur.toParent();
} else {
int k = _cur.kind();
if (k == -COMMENT || k == -PROCINST || k == -ATTR) {
_cur.toParent();
} else if (_cur.isContainer()) {
_cur.toLastAttr();
} else if (wasText && _cur.isText()) {
return _toPrevToken();
}
}
return _currentTokenType();
}
public Object _monitor() {
// TODO - some of these methods need not be protected by a
// gatway. This is one of them. Inline this.
return _cur._locale;
}
public boolean _toParent() {
Cur c = _cur.tempCur();
if (!c.toParent()) {
return false;
}
_cur.moveToCur(c);
c.release();
return true;
}
private static final class ChangeStampImpl implements ChangeStamp {
ChangeStampImpl(Locale l) {
_locale = l;
_versionStamp = _locale.version();
}
public boolean hasChanged() {
return _versionStamp != _locale.version();
}
private final Locale _locale;
private final long _versionStamp;
}
public ChangeStamp _getDocChangeStamp() {
return new ChangeStampImpl(_cur._locale);
}
//
// These simply delegate to the version of the method which takes XmlOptions
//
/**
* @deprecated XMLInputStream was deprecated by XMLStreamReader from STaX - jsr173 API.
*/
public XMLInputStream _newXMLInputStream() {
return _newXMLInputStream(null);
}
public XMLStreamReader _newXMLStreamReader() {
return _newXMLStreamReader(null);
}
public Node _newDomNode() {
return _newDomNode(null);
}
public InputStream _newInputStream() {
return _newInputStream(null);
}
public String _xmlText() {
return _xmlText(null);
}
public Reader _newReader() {
return _newReader(null);
}
public void _save(File file) throws IOException {
_save(file, null);
}
public void _save(OutputStream os) throws IOException {
_save(os, null);
}
public void _save(Writer w) throws IOException {
_save(w, null);
}
public void _save(ContentHandler ch, LexicalHandler lh) throws SAXException {
_save(ch, lh, null);
}
//
//
//
public XmlDocumentProperties _documentProperties() {
return Locale.getDocProps(_cur, true);
}
public XMLStreamReader _newXMLStreamReader(XmlOptions options) {
return Jsr173.newXmlStreamReader(_cur, options);
}
/**
* @deprecated XMLInputStream was deprecated by XMLStreamReader from STaX - jsr173 API.
*/
public XMLInputStream _newXMLInputStream(XmlOptions options) {
return new Saver.XmlInputStreamImpl(_cur, options);
}
public String _xmlText(XmlOptions options) {
assert isValid();
return new TextSaver(_cur, options, null).saveToString();
}
public InputStream _newInputStream(XmlOptions options) {
return new Saver.InputStreamSaver(_cur, options);
}
public Reader _newReader(XmlOptions options) {
return new Saver.TextReader(_cur, options);
}
public void _save(ContentHandler ch, LexicalHandler lh, XmlOptions options)
throws SAXException {
new Saver.SaxSaver(_cur, options, ch, lh);
}
public void _save(File file, XmlOptions options) throws IOException {
if (file == null) {
throw new IllegalArgumentException("Null file specified");
}
try (OutputStream os = new FileOutputStream(file)) {
_save(os, options);
}
}
public void _save(OutputStream os, XmlOptions options) throws IOException {
if (os == null) {
throw new IllegalArgumentException("Null OutputStream specified");
}
try (InputStream is = _newInputStream(options)) {
byte[] bytes = new byte[8192];
for (; ; ) {
int n = is.read(bytes);
if (n < 0) {
break;
}
os.write(bytes, 0, n);
}
}
}
public void _save(Writer w, XmlOptions options) throws IOException {
if (w == null) {
throw new IllegalArgumentException("Null Writer specified");
}
if (options != null && options.isSaveOptimizeForSpeed()) {
Saver.OptimizedForSpeedSaver.save(_cur, w); //ignore all other options
return;
}
try (Reader r = _newReader(options)) {
char[] chars = new char[8192];
for (; ; ) {
int n = r.read(chars);
if (n < 0) {
break;
}
w.write(chars, 0, n);
}
}
}
public Node _getDomNode() {
return (Node) _cur.getDom();
}
private boolean isDomFragment() {
if (!isStartdoc()) {
return true;
}
boolean seenElement = false;
XmlCursor c = newCursor();
int token = c.toNextToken().intValue();
try {
LOOP:
for (; ; ) {
switch (token) {
case TokenType.INT_START:
if (seenElement) {
return true;
}
seenElement = true;
token = c.toEndToken().intValue();
break;
case TokenType.INT_TEXT:
if (!Locale.isWhiteSpace(c.getChars())) {
return true;
}
token = c.toNextToken().intValue();
break;
case TokenType.INT_NONE:
case TokenType.INT_ENDDOC:
break LOOP;
case TokenType.INT_ATTR:
case TokenType.INT_NAMESPACE:
return true;
case TokenType.INT_END:
case TokenType.INT_COMMENT:
case TokenType.INT_PROCINST:
token = c.toNextToken().intValue();
break;
case TokenType.INT_STARTDOC:
assert false;
break LOOP;
}
}
} finally {
c.dispose();
}
return !seenElement;
}
public Node _newDomNode(XmlOptions options) {
// Must ignore inner options for compat with v1.
if (options != null && options.isSaveInner()) {
options = new XmlOptions(options);
options.setSaveInner(false);
}
return new DomSaver(_cur, isDomFragment(), options).saveDom();
}
public boolean _toCursor(Cursor other) {
assert _cur._locale == other._cur._locale;
_cur.moveToCur(other._cur);
return true;
}
public void _push() {
_cur.push();
}
public boolean _pop() {
return _cur.pop();
}
public void notifyChange() {
// Force any path to get exausted, cursor may be disposed, but still be on the notification
// list.
if (_cur != null) {
_getSelectionCount();
}
}
public void setNextChangeListener(ChangeListener listener) {
_nextChangeListener = listener;
}
public ChangeListener getNextChangeListener() {
return _nextChangeListener;
}
public void _selectPath(String path) {
_selectPath(path, null);
}
public void _selectPath(String pathExpr, XmlOptions options) {
_clearSelections();
assert _pathEngine == null;
_pathEngine = Path.getCompiledPath(pathExpr, options).execute(_cur, options);
_cur._locale.registerForChange(this);
}
public boolean _hasNextSelection() {
int curr = _currentSelection;
push();
try {
return _toNextSelection();
} finally {
_currentSelection = curr;
pop();
}
}
public boolean _toNextSelection() {
return _toSelection(_currentSelection + 1);
}
public boolean _toSelection(int i) {
if (i < 0) {
return false;
}
while (i >= _cur.selectionCount()) {
if (_pathEngine == null) {
return false;
}
if (!_pathEngine.next(_cur)) {
_pathEngine.release();
_pathEngine = null;
return false;
}
}
_cur.moveToSelection(_currentSelection = i);
return true;
}
public int _getSelectionCount() {
// Should never get to MAX_VALUE selection index, so, state should not change
_toSelection(Integer.MAX_VALUE);
return _cur.selectionCount();
}
public void _addToSelection() {
_toSelection(Integer.MAX_VALUE);
_cur.addToSelection();
}
public void _clearSelections() {
if (_pathEngine != null) {
_pathEngine.release();
_pathEngine = null;
}
_cur.clearSelection();
_currentSelection = -1;
}
public String _namespaceForPrefix(String prefix) {
if (!_cur.isContainer()) {
throw new IllegalStateException("Not on a container");
}
return _cur.namespaceForPrefix(prefix, true);
}
public String _prefixForNamespace(String ns) {
if (ns == null || ns.length() == 0) {
throw new IllegalArgumentException("Must specify a namespace");
}
// Note: I loosen this requirement in v2, can call this from anywhere
// if (!_cur.isContainer())
// throw new IllegalStateException( "Not on a container" );
return _cur.prefixForNamespace(ns, null, true);
}
public void _getAllNamespaces(Map<String,String> addToThis) {
if (!_cur.isContainer()) {
throw new IllegalStateException("Not on a container");
}
if (addToThis != null) {
Locale.getAllNamespaces(_cur, addToThis);
}
}
public XmlObject _getObject() {
return _cur.getObject();
}
public TokenType _prevTokenType() {
_cur.push();
TokenType tt = _toPrevToken();
_cur.pop();
return tt;
}
public boolean _hasNextToken() {
//return _cur.kind() != -ROOT;
return _cur._pos != Cur.END_POS || _cur._xobj.kind() != ROOT;
}
public boolean _hasPrevToken() {
return _cur.kind() != ROOT;
}
public TokenType _toFirstContentToken() {
if (!_cur.isContainer()) {
return TokenType.NONE;
}
_cur.next();
return currentTokenType();
}
public TokenType _toEndToken() {
if (!_cur.isContainer()) {
return TokenType.NONE;
}
_cur.toEnd();
return currentTokenType();
}
public boolean _toChild(String local) {
return _toChild(null, local);
}
public boolean _toChild(QName name) {
return _toChild(name, 0);
}
public boolean _toChild(int index) {
return _toChild(null, index);
}
public boolean _toChild(String uri, String local) {
validateLocalName(local);
return _toChild(_cur._locale.makeQName(uri, local), 0);
}
public boolean _toChild(QName name, int index) {
return Locale.toChild(_cur, name, index);
}
public int _toNextChar(int maxCharacterCount) {
return _cur.nextChars(maxCharacterCount);
}
public int _toPrevChar(int maxCharacterCount) {
return _cur.prevChars(maxCharacterCount);
}
public boolean _toPrevSibling() {
return Locale.toPrevSiblingElement(_cur);
}
public boolean _toLastChild() {
return Locale.toLastChildElement(_cur);
}
public boolean _toFirstChild() {
return Locale.toFirstChildElement(_cur);
}
public boolean _toNextSibling(String name) {
return _toNextSibling(new QName(name));
}
public boolean _toNextSibling(String uri, String local) {
validateLocalName(local);
return _toNextSibling(_cur._locale._qnameFactory.getQName(uri, local));
}
public boolean _toNextSibling(QName name) {
_cur.push();
while (___toNextSibling()) {
if (_cur.getName().equals(name)) {
_cur.popButStay();
return true;
}
}
_cur.pop();
return false;
}
public boolean _toFirstAttribute() {
return _cur.isContainer() && Locale.toFirstNormalAttr(_cur);
}
public boolean _toLastAttribute() {
if (_cur.isContainer()) {
_cur.push();
_cur.push();
boolean foundAttr = false;
while (_cur.toNextAttr()) {
if (_cur.isNormalAttr()) {
_cur.popButStay();
_cur.push();
foundAttr = true;
}
}
_cur.pop();
if (foundAttr) {
_cur.popButStay();
return true;
}
_cur.pop();
}
return false;
}
public boolean _toNextAttribute() {
return _cur.isAttr() && Locale.toNextNormalAttr(_cur);
}
public boolean _toPrevAttribute() {
return _cur.isAttr() && Locale.toPrevNormalAttr(_cur);
}
public String _getAttributeText(QName attrName) {
if (attrName == null) {
throw new IllegalArgumentException("Attr name is null");
}
if (!_cur.isContainer()) {
return null;
}
return _cur.getAttrValue(attrName);
}
public boolean _setAttributeText(QName attrName, String value) {
if (attrName == null) {
throw new IllegalArgumentException("Attr name is null");
}
validateLocalName(attrName.getLocalPart());
if (!_cur.isContainer()) {
return false;
}
_cur.setAttrValue(attrName, value);
return true;
}
public boolean _removeAttribute(QName attrName) {
if (attrName == null) {
throw new IllegalArgumentException("Attr name is null");
}
if (!_cur.isContainer()) {
return false;
}
return _cur.removeAttr(attrName);
}
public String _getTextValue() {
if (_cur.isText()) {
return _getChars();
}
if (!_cur.isNode()) {
throw new IllegalStateException("Can't get text value, current token can have no text value");
}
return _cur.hasChildren() ? Locale.getTextValue(_cur) : _cur.getValueAsString();
}
public int _getTextValue(char[] chars, int offset, int max) {
if (_cur.isText()) {
return _getChars(chars, offset, max);
}
if (chars == null) {
throw new IllegalArgumentException("char buffer is null");
}
if (offset < 0) {
throw new IllegalArgumentException("offset < 0");
}
if (offset >= chars.length) {
throw new IllegalArgumentException("offset off end");
}
if (max < 0) {
max = Integer.MAX_VALUE;
}
if (offset + max > chars.length) {
max = chars.length - offset;
}
if (!_cur.isNode()) {
throw new IllegalStateException("Can't get text value, current token can have no text value");
}
// If there are no children (hopefully the common case), I can get the text faster.
if (_cur.hasChildren()) {
return Locale.getTextValue(_cur, Locale.WS_PRESERVE, chars, offset, max);
}
// Fast way
Object src = _cur.getFirstChars();
if (_cur._cchSrc > max) {
_cur._cchSrc = max;
}
if (_cur._cchSrc <= 0) {
return 0;
}
CharUtil.getChars(chars, offset, src, _cur._offSrc, _cur._cchSrc);
return _cur._cchSrc;
}
private void setTextValue(Object src, int off, int cch) {
if (!_cur.isNode()) {
throw new IllegalStateException("Can't set text value, current token can have no text value");
}
_cur.moveNodeContents(null, false);
_cur.next();
_cur.insertChars(src, off, cch);
_cur.toParent();
}
public void _setTextValue(String text) {
if (text == null) {
text = "";
}
setTextValue(text, 0, text.length());
}
public void _setTextValue(char[] sourceChars, int offset, int length) {
if (length < 0) {
throw new IndexOutOfBoundsException("setTextValue: length < 0");
}
if (sourceChars == null) {
if (length > 0) {
throw new IllegalArgumentException("setTextValue: sourceChars == null");
}
setTextValue(null, 0, 0);
return;
}
if (offset < 0 || offset >= sourceChars.length) {
throw new IndexOutOfBoundsException("setTextValue: offset out of bounds");
}
if (offset + length > sourceChars.length) {
length = sourceChars.length - offset;
}
CharUtil cu = _cur._locale.getCharUtil();
setTextValue(cu.saveChars(sourceChars, offset, length), cu._offSrc, cu._cchSrc);
}
public String _getChars() {
return _cur.getCharsAsString();
}
public int _getChars(char[] buf, int off, int cch) {
int cchRight = _cur.cchRight();
if (cch < 0 || cch > cchRight) {
cch = cchRight;
}
if (buf == null || off >= buf.length) {
return 0;
}
if (buf.length - off < cch) {
cch = buf.length - off;
}
Object src = _cur.getChars(cch);
CharUtil.getChars(buf, off, src, _cur._offSrc, _cur._cchSrc);
return _cur._cchSrc;
}
public void _toStartDoc() {
_cur.toRoot();
}
public void _toEndDoc() {
_toStartDoc();
_cur.toEnd();
}
public int _comparePosition(Cursor other) {
int s = _cur.comparePosition(other._cur);
if (s == 2) {
throw new IllegalArgumentException("Cursors not in same document");
}
assert s >= -1 && s <= 1;
return s;
}
public boolean _isLeftOf(Cursor other) {
return _comparePosition(other) < 0;
}
public boolean _isAtSamePositionAs(Cursor other) {
return _cur.isSamePos(other._cur);
}
public boolean _isRightOf(Cursor other) {
return _comparePosition(other) > 0;
}
public XmlCursor _execQuery(String query) {
return _execQuery(query, null);
}
public XmlCursor _execQuery(String query, XmlOptions options) {
checkThisCursor();
return Query.cursorExecQuery(_cur, query, options);
}
public boolean _toBookmark(XmlBookmark bookmark) {
if (bookmark == null || !(bookmark._currentMark instanceof Bookmark)) {
return false;
}
Bookmark m = (Bookmark) bookmark._currentMark;
if (m._xobj == null || m._xobj._locale != _cur._locale) {
return false;
}
_cur.moveTo(m._xobj, m._pos);
return true;
}
public XmlBookmark _toNextBookmark(Object key) {
if (key == null) {
return null;
}
int cch;
_cur.push();
for (; ; ) {
// Move a minimal amount. If at text, move to a potential bookmark in the text.
if ((cch = _cur.cchRight()) > 1) {
_cur.nextChars(1);
_cur.nextChars((cch = _cur.firstBookmarkInChars(key, cch - 1)) >= 0 ? cch : -1);
} else if (_toNextToken().isNone()) {
_cur.pop();
return null;
}
XmlBookmark bm = getBookmark(key, _cur);
if (bm != null) {
_cur.popButStay();
return bm;
}
if (_cur.kind() == -ROOT) {
_cur.pop();
return null;
}
}
}
public XmlBookmark _toPrevBookmark(Object key) {
if (key == null) {
return null;
}
int cch;
_cur.push();
for (; ; ) {
// Move a minimal amount. If at text, move to a potential bookmark in the text.
if ((cch = _cur.cchLeft()) > 1) {
_cur.prevChars(1);
_cur.prevChars((cch = _cur.firstBookmarkInCharsLeft(key, cch - 1)) >= 0 ? cch : -1);
} else if (cch == 1) {
// _toPrevToken will not skip to the beginning of the text, it will go further
// so that the token to the right is not text. I need to simply skip to
// the beginning of the text ...
_cur.prevChars(1);
} else if (_toPrevToken().isNone()) {
_cur.pop();
return null;
}
XmlBookmark bm = getBookmark(key, _cur);
if (bm != null) {
_cur.popButStay();
return bm;
}
if (_cur.kind() == ROOT) {
_cur.pop();
return null;
}
}
}
public void _setBookmark(XmlBookmark bookmark) {
if (bookmark != null) {
if (bookmark.getKey() == null) {
throw new IllegalArgumentException("Annotation key is null");
}
// TODO - I Don't do weak bookmarks yet ... perhaps I'll never do them ....
bookmark._currentMark = _cur.setBookmark(bookmark.getKey(), bookmark);
}
}
static XmlBookmark getBookmark(Object key, Cur c) {
// TODO - I Don't do weak bookmarks yet ...
if (key == null) {
return null;
}
Object bm = c.getBookmark(key);
return bm instanceof XmlBookmark ? (XmlBookmark) bm : null;
}
public XmlBookmark _getBookmark(Object key) {
return key == null ? null : getBookmark(key, _cur);
}
public void _clearBookmark(Object key) {
if (key != null) {
_cur.setBookmark(key, null);
}
}
public void _getAllBookmarkRefs(Collection listToFill) {
if (listToFill != null) {
for (Bookmark b = _cur._xobj._bookmarks; b != null; b = b._next) {
if (b._value instanceof XmlBookmark) {
listToFill.add(b._value);
}
}
}
}
public boolean _removeXml() {
if (_cur.isRoot()) {
throw new IllegalStateException("Can't remove a whole document.");
}
if (_cur.isFinish()) {
return false;
}
assert _cur.isText() || _cur.isNode();
if (_cur.isText()) {
_cur.moveChars(null, -1);
} else {
_cur.moveNode(null);
}
return true;
}
public boolean _moveXml(Cursor to) {
to.checkInsertionValidity(_cur);
// Check for a no-op
if (_cur.isText()) {
int cchRight = _cur.cchRight();
assert cchRight > 0;
if (_cur.inChars(to._cur, cchRight, true)) {
return false;
}
_cur.moveChars(to._cur, cchRight);
to._cur.nextChars(cchRight);
return true;
}
if (_cur.contains(to._cur)) {
return false;
}
// Make a cur which will float to the right of the insertion
Cur c = to.tempCur();
_cur.moveNode(to._cur);
to._cur.moveToCur(c);
c.release();
return true;
}
public boolean _copyXml(Cursor to) {
to.checkInsertionValidity(_cur);
assert _cur.isText() || _cur.isNode();
Cur c = to.tempCur();
if (_cur.isText()) {
to._cur.insertChars(_cur.getChars(-1), _cur._offSrc, _cur._cchSrc);
} else {
_cur.copyNode(to._cur);
}
to._cur.moveToCur(c);
c.release();
return true;
}
public boolean _removeXmlContents() {
if (!_cur.isContainer()) {
return false;
}
_cur.moveNodeContents(null, false);
return true;
}
private boolean checkContentInsertionValidity(Cursor to) {
_cur.push();
_cur.next();
if (_cur.isFinish()) {
_cur.pop();
return false;
}
try {
to.checkInsertionValidity(_cur);
} catch (IllegalArgumentException e) {
_cur.pop();
throw e;
}
_cur.pop();
return true;
}
public boolean _moveXmlContents(Cursor to) {
if (!_cur.isContainer() || _cur.contains(to._cur)) {
return false;
}
if (!checkContentInsertionValidity(to)) {
return false;
}
Cur c = to.tempCur();
_cur.moveNodeContents(to._cur, false);
to._cur.moveToCur(c);
c.release();
return true;
}
public boolean _copyXmlContents(Cursor to) {
if (!_cur.isContainer() || _cur.contains(to._cur)) {
return false;
}
if (!checkContentInsertionValidity(to)) {
return false;
}
// I don't have a primitive to copy contents, make a copy of the node and them move the
// contents
Cur c = _cur._locale.tempCur();
_cur.copyNode(c);
Cur c2 = to._cur.tempCur();
c.moveNodeContents(to._cur, false);
c.release();
to._cur.moveToCur(c2);
c2.release();
return true;
}
public int _removeChars(int cch) {
int cchRight = _cur.cchRight();
if (cchRight == 0 || cch == 0) {
return 0;
}
if (cch < 0 || cch > cchRight) {
cch = cchRight;
}
_cur.moveChars(null, cch);
return _cur._cchSrc;
}
public int _moveChars(int cch, Cursor to) {
int cchRight = _cur.cchRight();
if (cchRight <= 0 || cch == 0) {
return 0;
}
if (cch < 0 || cch > cchRight) {
cch = cchRight;
}
to.checkInsertionValidity(_cur);
_cur.moveChars(to._cur, cch);
to._cur.nextChars(_cur._cchSrc);
return _cur._cchSrc;
}
public int _copyChars(int cch, Cursor to) {
int cchRight = _cur.cchRight();
if (cchRight <= 0 || cch == 0) {
return 0;
}
if (cch < 0 || cch > cchRight) {
cch = cchRight;
}
to.checkInsertionValidity(_cur);
to._cur.insertChars(_cur.getChars(cch), _cur._offSrc, _cur._cchSrc);
to._cur.nextChars(_cur._cchSrc);
return _cur._cchSrc;
}
public void _insertChars(String text) {
int l = text == null ? 0 : text.length();
if (l > 0) {
if (_cur.isRoot() || _cur.isAttr()) {
throw
new IllegalStateException("Can't insert before the document or an attribute.");
}
_cur.insertChars(text, 0, l);
_cur.nextChars(l);
}
}
//
// Inserting elements
//
public void _beginElement(String localName) {
_insertElementWithText(localName, null, null);
_toPrevToken();
}
public void _beginElement(String localName, String uri) {
_insertElementWithText(localName, uri, null);
_toPrevToken();
}
public void _beginElement(QName name) {
_insertElementWithText(name, null);
_toPrevToken();
}
public void _insertElement(String localName) {
_insertElementWithText(localName, null, null);
}
public void _insertElement(String localName, String uri) {
_insertElementWithText(localName, uri, null);
}
public void _insertElement(QName name) {
_insertElementWithText(name, null);
}
public void _insertElementWithText(String localName, String text) {
_insertElementWithText(localName, null, text);
}
public void _insertElementWithText(String localName, String uri, String text) {
validateLocalName(localName);
_insertElementWithText(_cur._locale.makeQName(uri, localName), text);
}
public void _insertElementWithText(QName name, String text) {
validateLocalName(name.getLocalPart());
Cur c = _cur._locale.tempCur();
c.createElement(name);
insertNode(c, text);
c.release();
}
//
//
//
public void _insertAttribute(String localName) {
_insertAttributeWithValue(localName, null);
}
public void _insertAttribute(String localName, String uri) {
_insertAttributeWithValue(localName, uri, null);
}
public void _insertAttribute(QName name) {
_insertAttributeWithValue(name, null);
}
public void _insertAttributeWithValue(String localName, String value) {
_insertAttributeWithValue(localName, null, value);
}
public void _insertAttributeWithValue(String localName, String uri, String value) {
validateLocalName(localName);
_insertAttributeWithValue(_cur._locale.makeQName(uri, localName), value);
}
public void _insertAttributeWithValue(QName name, String text) {
validateLocalName(name.getLocalPart());
Cur c = _cur._locale.tempCur();
c.createAttr(name);
insertNode(c, text);
c.release();
}
//
//
//
public void _insertNamespace(String prefix, String namespace) {
_insertAttributeWithValue(_cur._locale.createXmlns(prefix), namespace);
}
public void _insertComment(String text) {
Cur c = _cur._locale.tempCur();
c.createComment();
insertNode(c, text);
c.release();
}
public void _insertProcInst(String target, String text) {
validateLocalName(target);
if (Locale.beginsWithXml(target) && target.length() == 3) {
throw new IllegalArgumentException("Target is 'xml'");
}
Cur c = _cur._locale.tempCur();
c.createProcinst(target);
insertNode(c, text);
c.release();
}
public void _dump() {
_cur.dump();
}
//
//
//
//
//
//
//
private void checkThisCursor() {
if (_cur == null) {
throw new IllegalStateException("This cursor has been disposed");
}
}
private Cursor checkCursors(XmlCursor xOther) {
checkThisCursor();
if (xOther == null) {
throw new IllegalArgumentException("Other cursor is <null>");
}
if (!(xOther instanceof Cursor)) {
throw new IllegalArgumentException("Incompatible cursors: " + xOther);
}
Cursor other = (Cursor) xOther;
if (other._cur == null) {
throw new IllegalStateException("Other cursor has been disposed");
}
return other;
}
//
// The following operations have two cursors, and can be in different documents
//
private static final int MOVE_XML = 0;
private static final int COPY_XML = 1;
private static final int MOVE_XML_CONTENTS = 2;
private static final int COPY_XML_CONTENTS = 3;
private static final int MOVE_CHARS = 4;
private static final int COPY_CHARS = 5;
private int twoLocaleOp(XmlCursor xOther, int op, int arg) {
Cursor other = checkCursors(xOther);
Locale locale = _cur._locale;
Locale otherLocale = other._cur._locale;
if (locale == otherLocale) {
return syncWrapNoEnter(() -> twoLocaleOp(other, op, arg));
}
if (locale.noSync()) {
if (otherLocale.noSync()) {
return twoLocaleOp(other, op, arg);
} else {
synchronized (otherLocale) {
return twoLocaleOp(other, op, arg);
}
}
} else if (otherLocale.noSync()) {
synchronized (locale) {
return twoLocaleOp(other, op, arg);
}
}
boolean acquired = false;
try {
GlobalLock.acquire();
acquired = true;
synchronized (locale) {
synchronized (otherLocale) {
GlobalLock.release();
acquired = false;
return twoLocaleOp(other, op, arg);
}
}
} catch (InterruptedException e) {
throw new RuntimeException(e.getMessage(), e);
} finally {
if (acquired) {
GlobalLock.release();
}
}
}
private int twoLocaleOp(Cursor other, int op, int arg) {
Locale locale = _cur._locale;
Locale otherLocale = other._cur._locale;
locale.enter(otherLocale);
try {
switch (op) {
case MOVE_XML:
return _moveXml(other) ? 1 : 0;
case COPY_XML:
return _copyXml(other) ? 1 : 0;
case MOVE_XML_CONTENTS:
return _moveXmlContents(other) ? 1 : 0;
case COPY_XML_CONTENTS:
return _copyXmlContents(other) ? 1 : 0;
case MOVE_CHARS:
return _moveChars(arg, other);
case COPY_CHARS:
return _copyChars(arg, other);
default:
throw new RuntimeException("Unknown operation: " + op);
}
} finally {
locale.exit(otherLocale);
}
}
public boolean moveXml(XmlCursor xTo) {
return twoLocaleOp(xTo, MOVE_XML, 0) == 1;
}
public boolean copyXml(XmlCursor xTo) {
return twoLocaleOp(xTo, COPY_XML, 0) == 1;
}
public boolean moveXmlContents(XmlCursor xTo) {
return twoLocaleOp(xTo, MOVE_XML_CONTENTS, 0) == 1;
}
public boolean copyXmlContents(XmlCursor xTo) {
return twoLocaleOp(xTo, COPY_XML_CONTENTS, 0) == 1;
}
public int moveChars(int cch, XmlCursor xTo) {
return twoLocaleOp(xTo, MOVE_CHARS, cch);
}
public int copyChars(int cch, XmlCursor xTo) {
return twoLocaleOp(xTo, COPY_CHARS, cch);
}
//
// Special methods involving multiple cursors which can be in different locales, but do not
// require sync on both locales.
//
public boolean toCursor(XmlCursor xOther) {
// One may only move cursors within the same locale
Cursor other = checkCursors(xOther);
return _cur._locale == other._cur._locale &&
syncWrap(() -> _toCursor(other));
}
public boolean isInSameDocument(XmlCursor xOther) {
return xOther != null && _cur.isInSameTree(checkCursors(xOther)._cur);
}
//
// The following operations have two cursors, but they must be in the same document
//
private Cursor preCheck(XmlCursor xOther) {
Cursor other = checkCursors(xOther);
if (_cur._locale != other._cur._locale) {
throw new IllegalArgumentException("Cursors not in same document");
}
return other;
}
public int comparePosition(XmlCursor xOther) {
Cursor other = preCheck(xOther);
return syncWrap(() -> _comparePosition(other));
}
public boolean isLeftOf(XmlCursor xOther) {
Cursor other = preCheck(xOther);
return syncWrap(() -> _isLeftOf(other));
}
public boolean isAtSamePositionAs(XmlCursor xOther) {
Cursor other = preCheck(xOther);
return syncWrap(() -> _isAtSamePositionAs(other));
}
public boolean isRightOf(XmlCursor xOther) {
Cursor other = preCheck(xOther);
return syncWrap(() -> _isRightOf(other));
}
//
// Create a cursor from an Xobj -- used for XmlBookmark.createCursor
//
public static XmlCursor newCursor(Xobj x, int p) {
Locale l = x._locale;
if (l.noSync()) {
l.enter();
try {
return new Cursor(x, p);
} finally {
l.exit();
}
} else {
synchronized (l) {
l.enter();
try {
return new Cursor(x, p);
} finally {
l.exit();
}
}
}
}
//
// The following operations involve only one cursor
//
private boolean preCheck() {
checkThisCursor();
return _cur._locale.noSync();
}
public void dispose() {
if (_cur != null) {
syncWrap(this::_dispose);
}
}
public Object monitor() {
return syncWrap(this::_monitor);
}
public XmlDocumentProperties documentProperties() {
return syncWrap(this::_documentProperties);
}
public XmlCursor newCursor() {
return syncWrap(this::_newCursor);
}
public XMLStreamReader newXMLStreamReader() {
return syncWrap((Supplier<XMLStreamReader>) this::_newXMLStreamReader);
}
public XMLStreamReader newXMLStreamReader(XmlOptions options) {
return syncWrap(() -> _newXMLStreamReader(options));
}
/**
* @deprecated XMLInputStream was deprecated by XMLStreamReader from STaX - jsr173 API.
*/
public XMLInputStream newXMLInputStream() {
return syncWrap((Supplier<XMLInputStream>) this::_newXMLInputStream);
}
public String xmlText() {
return syncWrap((Supplier<String>) this::_xmlText);
}
public InputStream newInputStream() {
return syncWrap((Supplier<InputStream>) this::_newInputStream);
}
public Reader newReader() {
return syncWrap((Supplier<Reader>) this::_newReader);
}
public Node newDomNode() {
return syncWrap((Supplier<Node>) this::_newDomNode);
}
public Node getDomNode() {
return syncWrap(this::_getDomNode);
}
public void save(ContentHandler ch, LexicalHandler lh) throws SAXException {
syncWrapSAXEx(() -> _save(ch, lh));
}
public void save(File file) throws IOException {
syncWrapIOEx(() -> _save(file));
}
public void save(OutputStream os) throws IOException {
syncWrapIOEx(() -> _save(os));
}
public void save(Writer w) throws IOException {
syncWrapIOEx(() -> _save(w));
}
/**
* @deprecated XMLInputStream was deprecated by XMLStreamReader from STaX - jsr173 API.
*/
public XMLInputStream newXMLInputStream(XmlOptions options) {
return syncWrap(() -> _newXMLInputStream(options));
}
public String xmlText(XmlOptions options) {
return syncWrap(() -> _xmlText(options));
}
public InputStream newInputStream(XmlOptions options) {
return syncWrap(() -> _newInputStream(options));
}
public Reader newReader(XmlOptions options) {
return syncWrap(() -> _newReader(options));
}
public Node newDomNode(XmlOptions options) {
return syncWrap(() -> _newDomNode(options));
}
public void save(ContentHandler ch, LexicalHandler lh, XmlOptions options) throws SAXException {
syncWrapSAXEx(() -> _save(ch, lh, options));
}
public void save(File file, XmlOptions options) throws IOException {
syncWrapIOEx(() -> _save(file, options));
}
public void save(OutputStream os, XmlOptions options) throws IOException {
syncWrapIOEx(() -> _save(os, options));
}
public void save(Writer w, XmlOptions options) throws IOException {
syncWrapIOEx(() -> _save(w, options));
}
public void push() {
syncWrap(this::_push);
}
public boolean pop() {
return syncWrap(this::_pop);
}
public void selectPath(String path) {
syncWrap(() -> _selectPath(path));
}
public void selectPath(String path, XmlOptions options) {
syncWrap(() -> _selectPath(path, options));
}
public boolean hasNextSelection() {
return syncWrap(this::_hasNextSelection);
}
public boolean toNextSelection() {
return syncWrap(this::_toNextSelection);
}
public boolean toSelection(int i) {
return syncWrap(() -> _toSelection(i));
}
public int getSelectionCount() {
return syncWrap(this::_getSelectionCount);
}
public void addToSelection() {
syncWrap(this::_addToSelection);
}
public void clearSelections() {
syncWrap(this::_clearSelections);
}
public boolean toBookmark(XmlBookmark bookmark) {
return syncWrap(() -> _toBookmark(bookmark));
}
public XmlBookmark toNextBookmark(Object key) {
return syncWrap(() -> _toNextBookmark(key));
}
public XmlBookmark toPrevBookmark(Object key) {
return syncWrap(() -> _toPrevBookmark(key));
}
public QName getName() {
return syncWrap(this::_getName);
}
public void setName(QName name) {
syncWrap(() -> _setName(name));
}
public String namespaceForPrefix(String prefix) {
return syncWrap(() -> _namespaceForPrefix(prefix));
}
public String prefixForNamespace(String namespaceURI) {
return syncWrap(() -> _prefixForNamespace(namespaceURI));
}
public void getAllNamespaces(Map<String,String> addToThis) {
syncWrap(() -> _getAllNamespaces(addToThis));
}
public XmlObject getObject() {
return syncWrap(this::_getObject);
}
public TokenType currentTokenType() {
return syncWrapNoEnter(this::_currentTokenType);
}
public boolean isStartdoc() {
return syncWrapNoEnter(this::_isStartdoc);
}
public boolean isEnddoc() {
return syncWrapNoEnter(this::_isEnddoc);
}
public boolean isStart() {
return syncWrapNoEnter(this::_isStart);
}
public boolean isEnd() {
return syncWrapNoEnter(this::_isEnd);
}
public boolean isText() {
return syncWrapNoEnter(this::_isText);
}
public boolean isAttr() {
return syncWrapNoEnter(this::_isAttr);
}
public boolean isNamespace() {
return syncWrapNoEnter(this::_isNamespace);
}
public boolean isComment() {
return syncWrapNoEnter(this::_isComment);
}
public boolean isProcinst() {
return syncWrapNoEnter(this::_isProcinst);
}
public boolean isContainer() {
return syncWrapNoEnter(this::_isContainer);
}
public boolean isFinish() {
return syncWrapNoEnter(this::_isFinish);
}
public boolean isAnyAttr() {
return syncWrapNoEnter(this::_isAnyAttr);
}
public TokenType prevTokenType() {
return syncWrap(this::_prevTokenType);
}
public boolean hasNextToken() {
return syncWrapNoEnter(this::_hasNextToken);
}
public boolean hasPrevToken() {
return syncWrap(this::_hasPrevToken);
}
public TokenType toNextToken() {
return syncWrap(this::_toNextToken);
}
public TokenType toPrevToken() {
return syncWrap(this::_toPrevToken);
}
public TokenType toFirstContentToken() {
return syncWrap(this::_toFirstContentToken);
}
public TokenType toEndToken() {
return syncWrap(this::_toEndToken);
}
public int toNextChar(int cch) {
return syncWrap(() -> _toNextChar(cch));
}
public int toPrevChar(int cch) {
return syncWrap(() -> _toPrevChar(cch));
}
// public boolean _toNextSibling()
// {
// return Locale.toNextSiblingElement(_cur);
// }
public boolean ___toNextSibling() {
if (!_cur.hasParent()) {
return false;
}
Xobj parent = _cur.getParentNoRoot();
if (parent == null) {
_cur._locale.enter();
try {
parent = _cur.getParent();
} finally {
_cur._locale.exit();
}
}
return Locale.toNextSiblingElement(_cur, parent);
}
public boolean toNextSibling() {
return syncWrapNoEnter(this::___toNextSibling);
}
public boolean toPrevSibling() {
return syncWrap(this::_toPrevSibling);
}
public boolean toParent() {
return syncWrap(this::_toParent);
}
public boolean toFirstChild() {
return syncWrapNoEnter(this::_toFirstChild);
}
public boolean toLastChild() {
return syncWrap(this::_toLastChild);
}
public boolean toChild(String name) {
return syncWrap(() -> _toChild(name));
}
public boolean toChild(String namespace, String name) {
return syncWrap(() -> _toChild(namespace, name));
}
public boolean toChild(QName name) {
return syncWrap(() -> _toChild(name));
}
public boolean toChild(int index) {
return syncWrap(() -> _toChild(index));
}
public boolean toChild(QName name, int index) {
return syncWrap(() -> _toChild(name, index));
}
public boolean toNextSibling(String name) {
return syncWrap(() -> _toNextSibling(name));
}
public boolean toNextSibling(String namespace, String name) {
return syncWrap(() -> _toNextSibling(namespace, name));
}
public boolean toNextSibling(QName name) {
return syncWrap(() -> _toNextSibling(name));
}
public boolean toFirstAttribute() {
return syncWrapNoEnter(this::_toFirstAttribute);
}
public boolean toLastAttribute() {
return syncWrap(this::_toLastAttribute);
}
public boolean toNextAttribute() {
return syncWrap(this::_toNextAttribute);
}
public boolean toPrevAttribute() {
return syncWrap(this::_toPrevAttribute);
}
public String getAttributeText(QName attrName) {
return syncWrap(() -> _getAttributeText(attrName));
}
public boolean setAttributeText(QName attrName, String value) {
return syncWrap(() -> _setAttributeText(attrName, value));
}
public boolean removeAttribute(QName attrName) {
return syncWrap(() -> _removeAttribute(attrName));
}
public String getTextValue() {
return syncWrap((Supplier<String>) this::_getTextValue);
}
public int getTextValue(char[] chars, int offset, int cch) {
return syncWrap(() -> _getTextValue(chars, offset, cch));
}
public void setTextValue(String text) {
syncWrap(() -> _setTextValue(text));
}
public void setTextValue(char[] sourceChars, int offset, int length) {
syncWrap(() -> _setTextValue(sourceChars, offset, length));
}
public String getChars() {
return syncWrap((Supplier<String>) this::_getChars);
}
public int getChars(char[] chars, int offset, int cch) {
return syncWrap(() -> _getChars(chars, offset, cch));
}
public void toStartDoc() {
syncWrapNoEnter(this::_toStartDoc);
}
public void toEndDoc() {
syncWrapNoEnter(this::_toEndDoc);
}
public XmlCursor execQuery(String query) {
return syncWrap(() -> _execQuery(query));
}
public XmlCursor execQuery(String query, XmlOptions options) {
return syncWrap(() -> _execQuery(query, options));
}
public ChangeStamp getDocChangeStamp() {
return syncWrap(this::_getDocChangeStamp);
}
public void setBookmark(XmlBookmark bookmark) {
syncWrap(() -> _setBookmark(bookmark));
}
public XmlBookmark getBookmark(Object key) {
return syncWrap(() -> _getBookmark(key));
}
public void clearBookmark(Object key) {
syncWrap(() -> _clearBookmark(key));
}
public void getAllBookmarkRefs(Collection listToFill) {
syncWrap(() -> _getAllBookmarkRefs(listToFill));
}
public boolean removeXml() {
return syncWrap(this::_removeXml);
}
public boolean removeXmlContents() {
return syncWrap(this::_removeXmlContents);
}
public int removeChars(int cch) {
return syncWrap(() -> _removeChars(cch));
}
public void insertChars(String text) {
syncWrap(() -> _insertChars(text));
}
public void insertElement(QName name) {
syncWrap(() -> _insertElement(name));
}
public void insertElement(String localName) {
syncWrap(() -> _insertElement(localName));
}
public void insertElement(String localName, String uri) {
syncWrap(() -> _insertElement(localName, uri));
}
public void beginElement(QName name) {
syncWrap(() -> _beginElement(name));
}
public void beginElement(String localName) {
syncWrap(() -> _beginElement(localName));
}
public void beginElement(String localName, String uri) {
syncWrap(() -> _beginElement(localName, uri));
}
public void insertElementWithText(QName name, String text) {
syncWrap(() -> _insertElementWithText(name, text));
}
public void insertElementWithText(String localName, String text) {
syncWrap(() -> _insertElementWithText(localName, text));
}
public void insertElementWithText(String localName, String uri, String text) {
syncWrap(() -> _insertElementWithText(localName, uri, text));
}
public void insertAttribute(String localName) {
syncWrap(() -> _insertAttribute(localName));
}
public void insertAttribute(String localName, String uri) {
syncWrap(() -> _insertAttribute(localName, uri));
}
public void insertAttribute(QName name) {
syncWrap(() -> _insertAttribute(name));
}
public void insertAttributeWithValue(String name, String value) {
syncWrap(() -> _insertAttributeWithValue(name, value));
}
public void insertAttributeWithValue(String name, String uri, String value) {
syncWrap(() -> _insertAttributeWithValue(name, uri, value));
}
public void insertAttributeWithValue(QName name, String value) {
syncWrap(() -> _insertAttributeWithValue(name, value));
}
public void insertNamespace(String prefix, String namespace) {
syncWrap(() -> _insertNamespace(prefix, namespace));
}
public void insertComment(String text) {
syncWrap(() -> _insertComment(text));
}
public void insertProcInst(String target, String text) {
syncWrap(() -> _insertProcInst(target, text));
}
public void dump() {
syncWrap(this::_dump);
}
private interface WrapSAXEx {
void run() throws SAXException;
}
private interface WrapIOEx {
void run() throws IOException;
}
@SuppressWarnings("SynchronizeOnNonFinalField")
private void syncWrap(Runnable inner) {
if (preCheck()) {
syncWrapHelper(inner, true);
} else {
synchronized (_cur._locale) {
syncWrapHelper(inner, true);
}
}
}
@SuppressWarnings("SynchronizeOnNonFinalField")
private <T> T syncWrap(Supplier<T> inner) {
if (preCheck()) {
return syncWrapHelper(inner, true);
} else {
synchronized (_cur._locale) {
return syncWrapHelper(inner, true);
}
}
}
@SuppressWarnings("SynchronizeOnNonFinalField")
private <T> T syncWrapNoEnter(Supplier<T> inner) {
if (preCheck()) {
return syncWrapHelper(inner, false);
} else {
synchronized (_cur._locale) {
return syncWrapHelper(inner, false);
}
}
}
@SuppressWarnings("SynchronizeOnNonFinalField")
private void syncWrapNoEnter(Runnable inner) {
if (preCheck()) {
syncWrapHelper(inner, false);
} else {
synchronized (_cur._locale) {
syncWrapHelper(inner, false);
}
}
}
@SuppressWarnings("SynchronizeOnNonFinalField")
private void syncWrapSAXEx(WrapSAXEx inner) throws SAXException {
if (preCheck()) {
syncWrapHelper(inner);
} else {
synchronized (_cur._locale) {
syncWrapHelper(inner);
}
}
}
@SuppressWarnings("SynchronizeOnNonFinalField")
private void syncWrapIOEx(WrapIOEx inner) throws IOException {
if (preCheck()) {
syncWrapHelper(inner);
} else {
synchronized (_cur._locale) {
syncWrapHelper(inner);
}
}
}
private void syncWrapHelper(Runnable inner, final boolean enterLocale) {
final Locale l = _cur._locale;
if (enterLocale) {
l.enter();
}
try {
inner.run();
} finally {
if (enterLocale) {
l.exit();
}
}
}
private <T> T syncWrapHelper(Supplier<T> inner, final boolean enterLocale) {
final Locale l = _cur._locale;
if (enterLocale) {
l.enter();
}
try {
return inner.get();
} finally {
if (enterLocale) {
l.exit();
}
}
}
private void syncWrapHelper(WrapSAXEx inner) throws SAXException {
final Locale l = _cur._locale;
l.enter();
try {
inner.run();
} finally {
l.exit();
}
}
private void syncWrapHelper(WrapIOEx inner) throws IOException {
final Locale l = _cur._locale;
l.enter();
try {
inner.run();
} finally {
l.exit();
}
}
}