![JAR search and dependency download from the Maven repository](/logo.png)
org.apache.xmlbeans.impl.store.Locale Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aem-sdk-api Show documentation
Show all versions of aem-sdk-api Show documentation
The Adobe Experience Manager SDK
/* Copyright 2004-2018 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.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.xmlbeans.*;
import org.apache.xmlbeans.XmlCursor.XmlBookmark;
import org.apache.xmlbeans.impl.common.QNameHelper;
import org.apache.xmlbeans.impl.common.ResolverUtil;
import org.apache.xmlbeans.impl.common.SAXHelper;
import org.apache.xmlbeans.impl.common.XmlLocale;
import org.apache.xmlbeans.impl.store.Cur.Locations;
import org.apache.xmlbeans.impl.store.DomImpl.Dom;
import org.apache.xmlbeans.impl.store.Saaj.SaajCallback;
import org.w3c.dom.*;
import org.xml.sax.*;
import org.xml.sax.ext.DeclHandler;
import org.xml.sax.ext.LexicalHandler;
import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import static org.apache.xmlbeans.impl.values.TypeStore.*;
@SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter")
public final class Locale
implements DOMImplementation, SaajCallback, XmlLocale {
private static final Logger LOG = LogManager.getLogger(Locale.class);
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;
static final String _xsi = "http://www.w3.org/2001/XMLSchema-instance";
// static final String _schema = "http://www.w3.org/2001/XMLSchema";
static final String _openFragUri = "http://www.openuri.org/fragment";
static final String _xml1998Uri = "http://www.w3.org/XML/1998/namespace";
static final String _xmlnsUri = "http://www.w3.org/2000/xmlns/";
static final QName _xsiNil = new QName(_xsi, "nil", "xsi");
static final QName _xsiType = new QName(_xsi, "type", "xsi");
static final QName _xsiLoc = new QName(_xsi, "schemaLocation", "xsi");
static final QName _xsiNoLoc = new QName(_xsi, "noNamespaceSchemaLocation", "xsi");
static final QName _openuriFragment = new QName(_openFragUri, "fragment", "frag");
static final QName _xmlFragment = new QName("xml-fragment");
private Locale(SchemaTypeLoader stl, XmlOptions options) {
options = XmlOptions.maskNull(options);
// TODO - add option for no=sync, or make it all thread safe
//
// Also - have a thread local setting for thread safety? .. Perhaps something
// in the type loader which defines whether ot not sync is on????
_noSync = options.isUnsynchronized();
_tempFrames = new Cur[_numTempFramesLeft = 8];
// BUGBUG - this cannot be thread local ....
// BUGBUG - this cannot be thread local ....
// BUGBUG - this cannot be thread local .... uhh what, again?
//
// Lazy create this (loading up a locale should use the thread locale one)
// same goes for the qname factory .. use thread local for hte most part when loading
_qnameFactory = new DefaultQNameFactory(); //new LocalDocumentQNameFactory();
_locations = new Locations(this);
_schemaTypeLoader = stl;
_validateOnSet = options.isValidateOnSet();
//
// Check for Saaj implementation request
//
_saaj = options.getSaaj();
if (_saaj != null) {
_saaj.setCallback(this);
}
}
public static Locale getLocale(SchemaTypeLoader stl, XmlOptions options) {
if (stl == null) {
stl = XmlBeans.getContextTypeLoader();
}
options = XmlOptions.maskNull(options);
Object source = options.getUseSameLocale();
if (source == null) {
return new Locale(stl, options);
}
Locale l;
if (source instanceof Locale) {
l = (Locale) source;
} else if (source instanceof XmlTokenSource) {
l = (Locale) ((XmlTokenSource) source).monitor();
} else {
throw new IllegalArgumentException("Source locale not understood: " + source);
}
if (l._schemaTypeLoader != stl) {
throw new IllegalArgumentException(
"Source locale does not support same schema type loader");
}
if (l._saaj != null && l._saaj != options.getSaaj()) {
throw new IllegalArgumentException(
"Source locale does not support same saaj");
}
if (l._validateOnSet && !options.isValidateOnSet()) {
throw new IllegalArgumentException(
"Source locale does not support same validate on set");
}
// TODO - other things to check?
return l;
}
public static void associateSourceName(Cur c, XmlOptions options) {
String sourceName = options == null ? null : options.getDocumentSourceName();
if (sourceName != null) {
getDocProps(c, true).setSourceName(sourceName);
}
}
public static void autoTypeDocument(Cur c, SchemaType requestedType,
XmlOptions options)
throws XmlException {
assert c.isRoot();
// The type in the options overrides all sniffing
options = XmlOptions.maskNull(options);
SchemaType optionType = options.getDocumentType();
if (optionType != null) {
c.setType(optionType);
return;
}
SchemaType type = null;
// An xsi:type can be used to pick a type out of the loader, or used to refine
// a type with a name.
if (requestedType == null || requestedType.getName() != null) {
QName xsiTypeName = c.getXsiTypeName();
SchemaType xsiSchemaType =
xsiTypeName == null ?
null : c._locale._schemaTypeLoader.findType(xsiTypeName);
if (requestedType == null ||
requestedType.isAssignableFrom(xsiSchemaType)) {
type = xsiSchemaType;
}
}
// Look for a document element to establish type
if (type == null &&
(requestedType == null || requestedType.isDocumentType())) {
assert c.isRoot();
c.push();
QName docElemName =
!c.hasAttrs() && Locale.toFirstChildElement(c) &&
!Locale.toNextSiblingElement(c)
? c.getName() : null;
c.pop();
if (docElemName != null) {
type =
c._locale._schemaTypeLoader.findDocumentType(docElemName);
if (type != null && requestedType != null) {
QName requesteddocElemNameName = requestedType.getDocumentElementName();
if (!requesteddocElemNameName.equals(docElemName) &&
!requestedType.isValidSubstitution(docElemName)) {
throw
new XmlException("Element " +
QNameHelper.pretty(docElemName) +
" is not a valid " +
QNameHelper.pretty(requesteddocElemNameName) +
" document or a valid substitution.");
}
}
}
}
if (type == null && requestedType == null) {
c.push();
type =
Locale.toFirstNormalAttr(c) && !Locale.toNextNormalAttr(c)
?
c._locale._schemaTypeLoader.findAttributeType(c.getName()) :
null;
c.pop();
}
if (type == null) {
type = requestedType;
}
if (type == null) {
type = XmlBeans.NO_TYPE;
}
c.setType(type);
if (requestedType != null) {
if (type.isDocumentType()) {
verifyDocumentType(c, type.getDocumentElementName());
} else if (type.isAttributeType()) {
verifyAttributeType(c, type.getAttributeTypeAttributeName());
}
}
}
private static boolean namespacesSame(QName n1, QName n2) {
if (n1 == n2) {
return true;
}
if (n1 == null || n2 == null) {
return false;
}
return Objects.equals(n1.getNamespaceURI(), n2.getNamespaceURI());
}
private static void addNamespace(StringBuilder sb, QName name) {
if (name.getNamespaceURI() == null) {
sb.append("");
} else {
sb.append("\"");
sb.append(name.getNamespaceURI());
sb.append("\"");
}
}
private static void verifyDocumentType(Cur c, QName docElemName)
throws XmlException {
assert c.isRoot();
c.push();
try {
StringBuilder sb = null;
if (!Locale.toFirstChildElement(c) ||
Locale.toNextSiblingElement(c)) {
sb = new StringBuilder();
sb.append("The document is not a ");
sb.append(QNameHelper.pretty(docElemName));
sb.append(
c.isRoot() ?
": no document element" : ": multiple document elements");
} else {
QName name = c.getName();
if (!name.equals(docElemName)) {
sb = new StringBuilder();
sb.append("The document is not a ");
sb.append(QNameHelper.pretty(docElemName));
if (docElemName.getLocalPart().equals(name.getLocalPart())) {
sb.append(": document element namespace mismatch ");
sb.append("expected ");
addNamespace(sb, docElemName);
sb.append(" got ");
addNamespace(sb, name);
} else if (namespacesSame(docElemName, name)) {
sb.append(": document element local name mismatch expected ")
.append(docElemName.getLocalPart())
.append(" got ")
.append(name.getLocalPart());
} else {
sb.append(": document element mismatch got ");
sb.append(QNameHelper.pretty(name));
}
}
}
if (sb != null) {
XmlError err = XmlError.forCursor(sb.toString(),
new Cursor(c));
throw new XmlException(err.toString(), null, err);
}
} finally {
c.pop();
}
}
private static void verifyAttributeType(Cur c, QName attrName) throws XmlException {
assert c.isRoot();
c.push();
try {
StringBuilder sb = null;
if (!Locale.toFirstNormalAttr(c) || Locale.toNextNormalAttr(c)) {
sb = new StringBuilder();
sb.append("The document is not a ");
sb.append(QNameHelper.pretty(attrName));
sb.append(
c.isRoot() ? ": no attributes" : ": multiple attributes");
} else {
QName name = c.getName();
if (!name.equals(attrName)) {
sb = new StringBuilder();
sb.append("The document is not a ");
sb.append(QNameHelper.pretty(attrName));
if (attrName.getLocalPart().equals(name.getLocalPart())) {
sb.append(": attribute namespace mismatch ");
sb.append("expected ");
addNamespace(sb, attrName);
sb.append(" got ");
addNamespace(sb, name);
} else if (namespacesSame(attrName, name)) {
sb.append(": attribute local name mismatch ");
sb.append("expected ").append(attrName.getLocalPart());
sb.append(" got ").append(name.getLocalPart());
} else {
sb.append(": attribute element mismatch ");
sb.append("got ");
sb.append(QNameHelper.pretty(name));
}
}
}
if (sb != null) {
XmlError err = XmlError.forCursor(sb.toString(),
new Cursor(c));
throw new XmlException(err.toString(), null, err);
}
} finally {
c.pop();
}
}
static boolean isFragmentQName(QName name) {
return name.equals(Locale._openuriFragment) ||
name.equals(Locale._xmlFragment);
}
static boolean isFragment(Cur start, Cur end) {
assert !end.isAttr();
start.push();
end.push();
int numDocElems = 0;
boolean isFrag = false;
while (!start.isSamePos(end)) {
int k = start.kind();
if (k == ATTR) {
break;
}
if (k == TEXT && !isWhiteSpace(start.getCharsAsString())) {
isFrag = true;
break;
}
if (k == ELEM && ++numDocElems > 1) {
isFrag = true;
break;
}
// Move to next token
if (k != TEXT) {
start.toEnd();
}
start.next();
}
start.pop();
end.pop();
return isFrag || numDocElems != 1;
}
public static XmlObject newInstance(SchemaTypeLoader stl, SchemaType type, XmlOptions options) {
try {
return syncWrap(stl, options, (l) -> {
Cur c = l.tempCur();
SchemaType sType = XmlOptions.maskNull(options).getDocumentType();
if (sType == null) {
sType = type == null ? XmlObject.type : type;
}
if (sType.isDocumentType()) {
c.createDomDocumentRoot();
} else {
c.createRoot();
}
c.setType(sType);
XmlObject x = (XmlObject) c.getUser();
c.release();
return x;
});
} catch (XmlException | IOException e) {
assert false : "newInstance doesn't throw XmlException or IOException";
throw new RuntimeException(e);
}
}
public static DOMImplementation newDomImplementation(SchemaTypeLoader stl, XmlOptions options) {
return getLocale(stl, options);
}
private interface SyncWrapFun {
T parse(Locale l) throws XmlException, IOException;
}
private static T syncWrap(SchemaTypeLoader stl, XmlOptions options, SyncWrapFun fun)
throws XmlException, IOException {
Locale l = getLocale(stl, options);
if (l.noSync()) {
l.enter();
try {
return fun.parse(l);
} finally {
l.exit();
}
} else {
synchronized (l) {
l.enter();
try {
return fun.parse(l);
} finally {
l.exit();
}
}
}
}
public static XmlObject parseToXmlObject(SchemaTypeLoader stl, String xmlText, SchemaType type, XmlOptions options)
throws XmlException {
try {
return syncWrap(stl, options, (l) -> {
try (Reader r = new StringReader(xmlText)) {
Cur c = getSaxLoader(options).load(l, new InputSource(r), options);
autoTypeDocument(c, type, options);
XmlObject x = (XmlObject) c.getUser();
c.release();
return x;
}
});
} catch (IOException e) {
assert false : "StringReader should not throw IOException";
throw new XmlException(e.getMessage(), e);
}
}
public static XmlObject parseToXmlObject(SchemaTypeLoader stl, XMLStreamReader xsr, SchemaType type, XmlOptions options)
throws XmlException {
try {
return syncWrap(stl, options, (l) -> {
Cur c;
try {
c = l.loadXMLStreamReader(xsr, options);
} catch (XMLStreamException e) {
throw new XmlException(e.getMessage(), e);
}
autoTypeDocument(c, type, options);
XmlObject x = (XmlObject) c.getUser();
c.release();
return x;
});
} catch (IOException e) {
assert false : "doesn't throw IOException";
throw new RuntimeException(e);
}
}
private static void lineNumber(XMLStreamReader xsr, LoadContext context) {
javax.xml.stream.Location loc = xsr.getLocation();
if (loc != null) {
context.lineNumber(loc.getLineNumber(), loc.getColumnNumber(),
loc.getCharacterOffset());
}
}
private void doAttributes(XMLStreamReader xsr, LoadContext context) {
int n = xsr.getAttributeCount();
for (int a = 0; a < n; a++) {
context.attr(xsr.getAttributeLocalName(a),
xsr.getAttributeNamespace(a),
xsr.getAttributePrefix(a),
xsr.getAttributeValue(a));
}
}
private void doNamespaces(XMLStreamReader xsr, LoadContext context) {
int n = xsr.getNamespaceCount();
for (int a = 0; a < n; a++) {
String prefix = xsr.getNamespacePrefix(a);
if (prefix == null || prefix.length() == 0) {
context.attr("xmlns", _xmlnsUri, null,
xsr.getNamespaceURI(a));
} else {
context.attr(prefix, _xmlnsUri, "xmlns",
xsr.getNamespaceURI(a));
}
}
}
private Cur loadXMLStreamReader(XMLStreamReader xsr, XmlOptions options)
throws XMLStreamException {
options = XmlOptions.maskNull(options);
boolean lineNums = options.isLoadLineNumbers();
String encoding = null, version = null;
boolean standAlone = false;
LoadContext context = new Cur.CurLoadContext(this, options);
int depth = 0;
events:
for (int eventType = xsr.getEventType(); ; eventType = xsr.next()) {
switch (eventType) {
case XMLStreamReader.START_DOCUMENT: {
depth++;
encoding = xsr.getCharacterEncodingScheme();
version = xsr.getVersion();
standAlone = xsr.isStandalone();
if (lineNums) {
lineNumber(xsr, context);
}
break;
}
case XMLStreamReader.END_DOCUMENT: {
depth--;
if (lineNums) {
lineNumber(xsr, context);
}
break events;
}
case XMLStreamReader.START_ELEMENT: {
depth++;
context.startElement(xsr.getName());
if (lineNums) {
lineNumber(xsr, context);
}
doAttributes(xsr, context);
doNamespaces(xsr, context);
break;
}
case XMLStreamReader.END_ELEMENT: {
depth--;
context.endElement();
if (lineNums) {
lineNumber(xsr, context);
}
break;
}
case XMLStreamReader.CHARACTERS:
case XMLStreamReader.CDATA: {
context.text(xsr.getTextCharacters(), xsr.getTextStart(),
xsr.getTextLength());
if (lineNums) {
lineNumber(xsr, context);
}
break;
}
case XMLStreamReader.COMMENT: {
String comment = xsr.getText();
context.comment(comment);
if (lineNums) {
lineNumber(xsr, context);
}
break;
}
case XMLStreamReader.PROCESSING_INSTRUCTION: {
context.procInst(xsr.getPITarget(), xsr.getPIData());
if (lineNums) {
lineNumber(xsr, context);
}
break;
}
case XMLStreamReader.ATTRIBUTE: {
doAttributes(xsr, context);
break;
}
case XMLStreamReader.NAMESPACE: {
doNamespaces(xsr, context);
break;
}
case XMLStreamReader.ENTITY_REFERENCE: {
context.text(xsr.getText());
break;
}
case XMLStreamReader.SPACE:
case XMLStreamReader.DTD:
break;
default:
throw new RuntimeException("Unhandled xml event type: " + eventType);
}
if (!xsr.hasNext() || depth <= 0) {
break;
}
}
Cur c = context.finish();
associateSourceName(c, options);
XmlDocumentProperties props = getDocProps(c, true);
props.setEncoding(encoding);
props.setVersion(version);
props.setStandalone(standAlone);
return c;
}
public static XmlObject parseToXmlObject(SchemaTypeLoader stl, InputStream is, SchemaType type, XmlOptions options)
throws XmlException, IOException {
return syncWrap(stl, options, (l) -> {
Cur c = getSaxLoader(options).load(l, new InputSource(is), options);
autoTypeDocument(c, type, options);
XmlObject x = (XmlObject) c.getUser();
c.release();
return x;
});
}
public static XmlObject parseToXmlObject(SchemaTypeLoader stl, Reader reader, SchemaType type, XmlOptions options)
throws XmlException, IOException {
return syncWrap(stl, options, (l) -> {
Cur c = getSaxLoader(options).load(l, new InputSource(reader), options);
autoTypeDocument(c, type, options);
XmlObject x = (XmlObject) c.getUser();
c.release();
return x;
});
}
public static XmlObject parseToXmlObject(SchemaTypeLoader stl, Node node, SchemaType type, XmlOptions options)
throws XmlException {
try {
return syncWrap(stl, options, (l) -> {
LoadContext context = new Cur.CurLoadContext(l, options);
l.loadNode(node, context);
Cur c = context.finish();
associateSourceName(c, options);
autoTypeDocument(c, type, options);
XmlObject x = (XmlObject) c.getUser();
c.release();
return x;
});
} catch (IOException e) {
assert false : "Doesn't throw IOException";
throw new RuntimeException(e);
}
}
private void loadNodeChildren(Node n, LoadContext context) {
for (Node c = n.getFirstChild(); c != null; c = c.getNextSibling()) {
loadNode(c, context);
}
}
public void loadNode(Node n, LoadContext context) {
switch (n.getNodeType()) {
case Node.DOCUMENT_NODE:
case Node.DOCUMENT_FRAGMENT_NODE:
case Node.ENTITY_REFERENCE_NODE: {
loadNodeChildren(n, context);
break;
}
case Node.ELEMENT_NODE: {
context.startElement(
makeQualifiedQName(n.getNamespaceURI(), n.getNodeName()));
NamedNodeMap attrs = n.getAttributes();
for (int i = 0; i < attrs.getLength(); i++) {
Node a = attrs.item(i);
String attrName = a.getNodeName();
String attrValue = a.getNodeValue();
if (attrName.toLowerCase(java.util.Locale.ROOT).startsWith("xmlns")) {
if (attrName.length() == 5) {
context.xmlns(null, attrValue);
} else {
context.xmlns(attrName.substring(6), attrValue);
}
} else {
context.attr(
makeQualifiedQName(a.getNamespaceURI(), attrName),
attrValue);
}
}
loadNodeChildren(n, context);
context.endElement();
break;
}
case Node.TEXT_NODE:
case Node.CDATA_SECTION_NODE: {
context.text(n.getNodeValue());
break;
}
case Node.COMMENT_NODE: {
context.comment(n.getNodeValue());
break;
}
case Node.PROCESSING_INSTRUCTION_NODE: {
context.procInst(n.getNodeName(), n.getNodeValue());
break;
}
case Node.DOCUMENT_TYPE_NODE:
case Node.ENTITY_NODE:
case Node.NOTATION_NODE: {
Node next = n.getNextSibling();
if (next != null) {
loadNode(next, context);
}
break;
}
case Node.ATTRIBUTE_NODE: {
throw new RuntimeException("Unexpected node");
}
}
}
//
//
//
private static class XmlSaxHandlerImpl
extends SaxHandler
implements XmlSaxHandler {
XmlSaxHandlerImpl(Locale l, SchemaType type, XmlOptions options) {
super(null);
_options = options;
_type = type;
// Because SAX loading is not atomic with respect to XmlBeans, I can't use the default
// thread local CharUtil. Instruct the SaxHandler (and the LoadContext, eventually)
// to use the Locale specific CharUtil.
XmlOptions saxHandlerOptions = new XmlOptions(options);
saxHandlerOptions.setLoadUseLocaleCharUtil(true);
initSaxHandler(l, saxHandlerOptions);
}
public ContentHandler getContentHandler() {
return _context == null ? null : this;
}
public LexicalHandler getLexicalHandler() {
return _context == null ? null : this;
}
public void bookmarkLastEvent(XmlBookmark mark) {
_context.bookmarkLastNonAttr(mark);
}
public void bookmarkLastAttr(QName attrName, XmlBookmark mark) {
_context.bookmarkLastAttr(attrName, mark);
}
public XmlObject getObject()
throws XmlException {
if (_context == null) {
return null;
}
_locale.enter();
try {
Cur c = _context.finish();
autoTypeDocument(c, _type, _options);
XmlObject x = (XmlObject) c.getUser();
c.release();
_context = null;
return x;
} finally {
_locale.exit();
}
}
private final SchemaType _type;
private final XmlOptions _options;
}
public static XmlSaxHandler newSaxHandler(SchemaTypeLoader stl, SchemaType type, XmlOptions options) {
try {
return syncWrap(stl, options, (l) -> new XmlSaxHandlerImpl(l, type, options));
} catch (XmlException | IOException e) {
assert false : "XmlException or IOException is not thrown";
throw new RuntimeException(e);
}
}
// TODO (ericvas ) - have a qname factory here so that the same factory may be
// used by the parser. This factory would probably come from my
// high speed parser. Otherwise, use a thread local on
QName makeQName(String uri, String localPart) {
assert localPart != null && localPart.length() > 0;
// TODO - make sure name is a well formed name?
return _qnameFactory.getQName(uri, localPart);
}
QName makeQNameNoCheck(String uri, String localPart) {
return _qnameFactory.getQName(uri, localPart);
}
QName makeQName(String uri, String local, String prefix) {
return _qnameFactory.getQName(uri, local, prefix == null ? "" : prefix);
}
QName makeQualifiedQName(String uri, String qname) {
if (qname == null) {
qname = "";
}
int i = qname.indexOf(':');
return i < 0
?
_qnameFactory.getQName(uri, qname)
:
_qnameFactory.getQName(uri, qname.substring(i + 1),
qname.substring(0, i));
}
static private class DocProps
extends XmlDocumentProperties {
private final HashMap
© 2015 - 2025 Weber Informatics LLC | Privacy Policy