Skip to content

Commit 2b35cf3

Browse files
author
Nico Verwer
committed
Merge remote-tracking branch 'evolvedbinary/develop-6.x.x' into develop-6.x.x
2 parents 55dbb6c + 5818c56 commit 2b35cf3

File tree

24 files changed

+1366
-459
lines changed

24 files changed

+1366
-459
lines changed

exist-core/pom.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -712,6 +712,7 @@
712712
<exclude>src/test/java/org/exist/xquery/functions/session/AttributeTest.java</exclude>
713713
<exclude>src/test/java/org/exist/xquery/functions/xmldb/XMLDBAuthenticateTest.java</exclude>
714714
<exclude>src/main/java/org/exist/xquery/functions/util/Eval.java</exclude>
715+
<exclude>src/main/java/org/exist/xquery/pragmas/TimePragma.java</exclude>
715716
<exclude>src/test/java/org/exist/xquery/util/URIUtilsTest.java</exclude>
716717
<exclude>src/main/java/org/exist/xquery/value/ArrayListValueSequence.java</exclude>
717718
<exclude>src/test/java/org/exist/xquery/value/BifurcanMapTest.java</exclude>
@@ -862,6 +863,7 @@ The original license statement is also included below.]]></preamble>
862863
<include>src/test/java/org/exist/xquery/functions/session/AttributeTest.java</include>
863864
<include>src/test/java/org/exist/xquery/functions/xmldb/XMLDBAuthenticateTest.java</include>
864865
<include>src/main/java/org/exist/xquery/functions/util/Eval.java</include>
866+
<include>src/main/java/org/exist/xquery/pragmas/TimePragma.java</include>
865867
<include>src/test/java/org/exist/xquery/util/URIUtilsTest.java</include>
866868
<include>src/main/java/org/exist/xquery/value/ArrayListValueSequence.java</include>
867869
<include>src/test/java/org/exist/xquery/value/BifurcanMapTest.java</include>

exist-core/src/main/java/org/exist/dom/QName.java

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ public class QName implements Comparable<QName> {
4141

4242
public static final String WILDCARD = "*";
4343
private static final char COLON = ':';
44+
private static final char LEFT_BRACE = '{';
45+
private static final char RIGHT_BRACE = '}';
4446

4547
public static final QName EMPTY_QNAME = new QName("", XMLConstants.NULL_NS_URI);
4648
public static final QName DOCUMENT_QNAME = EMPTY_QNAME;
@@ -126,32 +128,44 @@ public byte getNameType() {
126128
return nameType;
127129
}
128130

131+
/**
132+
* Get a string representation of this qualified name.
133+
*
134+
* Will either be of the format `local-name` or `prefix:local-name`.
135+
*
136+
* @return the string representation of this qualified name.
137+
* */
129138
public String getStringValue() {
130-
if (prefix != null && prefix.length() > 0) {
131-
return prefix + COLON + localPart;
132-
}
133-
return localPart;
139+
return getStringRepresentation(false);
134140
}
135141

136142
/**
137-
* @deprecated Use for debugging purpose only,
138-
* use {@link #getStringValue()} for production
143+
* Get a string representation of this qualified name.
144+
*
145+
* Will either be of the format `local-name`, `prefix:local-name`, or `{namespace}local-name`.
146+
*
147+
* @return the string representation of this qualified name.
139148
*/
140149
@Override
141150
public String toString() {
142-
//TODO : remove this copy of getStringValue()
143-
return getStringValue();
144-
//TODO : replace by something like this
145-
/*
146-
if (prefix != null && prefix.length() > 0)
151+
return getStringRepresentation(true);
152+
}
153+
154+
/**
155+
* Get a string representation of this qualified name.
156+
*
157+
* @param showNsWithoutPrefix true if the namespace should be shown even when there is no prefix, false otherwise.
158+
* When shown, it will be output using Clark notation, e.g. `{http://namespace}local-name`.
159+
*
160+
* @return the string representation of this qualified name.
161+
*/
162+
private String getStringRepresentation(final boolean showNsWithoutPrefix) {
163+
if (prefix != null && !prefix.isEmpty()) {
147164
return prefix + COLON + localPart;
148-
if (hasNamespace()) {
149-
if (prefix != null && prefix.length() > 0)
150-
return "{" + namespaceURI + "}" + prefix + COLON + localPart;
151-
return "{" + namespaceURI + "}" + localPart;
152-
} else
153-
return localPart;
154-
*/
165+
} else if (showNsWithoutPrefix && namespaceURI != null && !XMLConstants.NULL_NS_URI.equals(namespaceURI)) {
166+
return LEFT_BRACE + namespaceURI + RIGHT_BRACE + localPart;
167+
}
168+
return localPart;
155169
}
156170

157171
/**

exist-core/src/main/java/org/exist/storage/NodePath.java

Lines changed: 63 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,22 @@
3333

3434

3535
/**
36+
* Represents a Node Path.
37+
*
38+
* Internally the node path is held as an array of {@link QName} components.
39+
* Upon construction the array of `components` is sized such that it will be exactly
40+
* what is required to represent the Node Path.
41+
* Mutation operations however will over-allocate the array as an optmisation, so that
42+
* we need not allocate/free memory on every mutation operation, but only
43+
* every {@link #DEFAULT_NODE_PATH_SIZE} operations.
44+
*
45+
* @author <a href="mailto:[email protected]">Adam Retter</a>
3646
* @author wolf
37-
* @author Adam Retter
3847
*/
3948
public class NodePath implements Comparable<NodePath> {
4049

41-
private static final int DEFAULT_NODE_PATH_SIZE = 5;
50+
static final int DEFAULT_NODE_PATH_SIZE = 4;
51+
static final int MAX_OVER_ALLOCATION_FACTOR = 2;
4252

4353
private static final Logger LOG = LogManager.getLogger(NodePath.class);
4454

@@ -89,21 +99,33 @@ public boolean includeDescendants() {
8999
}
90100

91101
public void append(final NodePath other) {
92-
// expand the array
93-
final int newLength = pos + other.length();
94-
this.components = Arrays.copyOf(components, newLength);
95-
System.arraycopy(other.components, 0, components, pos, other.length());
96-
this.pos = newLength;
102+
// do we have enough space to accommodate the components from `other`
103+
final int numOtherComponentsToAppend = other.length();
104+
allocateIfNeeded(numOtherComponentsToAppend);
105+
106+
// at this point we have enough space, append the components from `other`
107+
System.arraycopy(other.components, 0, components, pos, numOtherComponentsToAppend);
108+
this.pos += numOtherComponentsToAppend;
97109
}
98110

99111
public void addComponent(final QName component) {
100-
if (pos == components.length) {
101-
// extend the array
102-
this.components = Arrays.copyOf(components, pos + 1);
103-
}
112+
// do we have enough space to add the component
113+
allocateIfNeeded(1);
114+
115+
// at this point we have enough space, add the component
104116
components[pos++] = component;
105117
}
106118

119+
private void allocateIfNeeded(final int numOtherComponentsToAppend) {
120+
final int available = components.length - pos;
121+
if (available < numOtherComponentsToAppend) {
122+
// we need more space, allocate a multiple of DEFAULT_NODE_PATH_SIZE
123+
final int allocationFactor = (int) Math.ceil((numOtherComponentsToAppend - available + components.length) / ((float) DEFAULT_NODE_PATH_SIZE));
124+
final int newSize = allocationFactor * DEFAULT_NODE_PATH_SIZE;
125+
this.components = Arrays.copyOf(components, newSize);
126+
}
127+
}
128+
107129
/**
108130
* Remove the Last Component from the NodePath.
109131
*
@@ -117,8 +139,8 @@ public void removeLastComponent() {
117139
}
118140

119141
public void reset() {
120-
// when resetting if this object has twice the capacity of a new object, then set it back to the default capacity
121-
if (pos > DEFAULT_NODE_PATH_SIZE * 2) {
142+
// when resetting if this object has more than twice the capacity of a new object, then set it back to the default capacity
143+
if (pos > DEFAULT_NODE_PATH_SIZE * MAX_OVER_ALLOCATION_FACTOR) {
122144
components = new QName[DEFAULT_NODE_PATH_SIZE];
123145
} else {
124146
Arrays.fill(components, null);
@@ -130,6 +152,18 @@ public int length() {
130152
return pos;
131153
}
132154

155+
/**
156+
* Return the size of the components array.
157+
*
158+
* This function is intentionally marked as package-private
159+
* so that it may only be called for testing purposes!
160+
*
161+
* @return the size of the components array.
162+
*/
163+
int componentsSize() {
164+
return components.length;
165+
}
166+
133167
protected void reverseComponents() {
134168
for (int i = 0; i < pos / 2; ++i) {
135169
QName tmp = components[i];
@@ -290,10 +324,24 @@ private void init(@Nullable final Map<String, String> namespaces, final String p
290324

291325
@Override
292326
public boolean equals(final Object obj) {
293-
if (obj != null && obj instanceof NodePath) {
327+
if (this == obj) {
328+
return true;
329+
}
330+
331+
if (obj instanceof NodePath) {
294332
final NodePath otherNodePath = (NodePath) obj;
295-
return Arrays.equals(components, otherNodePath.components);
333+
334+
// NOTE(AR) we cannot use Array.equals on the components of the NodePaths as they may be over-allocated!
335+
if (pos == otherNodePath.pos) {
336+
for (int i = 0; i < pos; i++) {
337+
if (!components[i].equals(otherNodePath.components[i])) {
338+
return false;
339+
}
340+
}
341+
return true;
342+
}
296343
}
344+
297345
return false;
298346
}
299347

exist-core/src/main/java/org/exist/xmldb/RemoteCollection.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,7 @@ private void store(final RemoteXMLResource res) throws XMLDBException {
521521
} catch (final URISyntaxException e) {
522522
throw new XMLDBException(ErrorCodes.INVALID_URI, e);
523523
}
524+
params.add(res.getMimeType());
524525
params.add(1);
525526
if (res.getCreationTime() != null) {
526527
params.add(res.getCreationTime());

exist-core/src/main/java/org/exist/xmlrpc/RpcAPI.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -545,18 +545,27 @@ boolean parse(byte[] xmlData, String docName)
545545
*
546546
* @param xmlData The document data
547547
* @param docName The path where the document will be stored
548+
* @param mimeType the mimeType to check for
548549
* @param overwrite Overwrite an existing document with the same path?
550+
* @param created Specifies the creattion date
551+
* @param modified Specifies the last modification date
549552
* @return true, if the document is valid XML
550553
* @throws EXistException If an internal error occurs
551554
* @throws PermissionDeniedException If the current user is not allowed to perform this action
552555
* @throws URISyntaxException If the URI contains syntax errors
553556
*/
554-
boolean parse(byte[] xmlData, String docName, int overwrite)
557+
boolean parse(byte[] xmlData, String docName, String mimeType, int overwrite, Date created, Date modified)
555558
throws EXistException, PermissionDeniedException, URISyntaxException;
556559

557560
boolean parse(byte[] xmlData, String docName, int overwrite, Date created, Date modified)
558561
throws EXistException, PermissionDeniedException, URISyntaxException;
559562

563+
boolean parse(byte[] xmlData, String docName, String mimeType, int overwrite)
564+
throws EXistException, PermissionDeniedException, URISyntaxException;
565+
566+
boolean parse(byte[] xmlData, String docName, int overwrite)
567+
throws EXistException, PermissionDeniedException, URISyntaxException;
568+
560569
boolean parse(String xml, String docName, int overwrite)
561570
throws EXistException, PermissionDeniedException, URISyntaxException;
562571

exist-core/src/main/java/org/exist/xmlrpc/RpcConnection.java

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1326,18 +1326,24 @@ private boolean hasCollection(final XmldbURI collUri) throws EXistException, Per
13261326

13271327
@Override
13281328
public boolean parse(byte[] xml, String documentPath, int overwrite) throws URISyntaxException, EXistException, PermissionDeniedException {
1329-
return parse(xml, documentPath, overwrite, null, null);
1329+
return parse(xml, documentPath, null, overwrite, null, null);
1330+
}
1331+
1332+
@Override
1333+
public boolean parse(final byte[] xml, final String documentPath, final String mimeType, final int overwrite) throws URISyntaxException, EXistException, PermissionDeniedException {
1334+
return parse(xml, documentPath, mimeType, overwrite, null, null);
13301335
}
13311336

13321337
@Override
13331338
public boolean parse(final byte[] xml, final String documentPath,
13341339
final int overwrite, final Date created, final Date modified) throws URISyntaxException, EXistException, PermissionDeniedException {
1335-
return parse(xml, XmldbURI.xmldbUriFor(documentPath), overwrite, created, modified);
1340+
return parse(xml, documentPath, null, overwrite, created, modified);
13361341
}
13371342

1338-
private boolean parse(final byte[] xml, final XmldbURI docUri,
1339-
final int overwrite, @Nullable final Date created, @Nullable final Date modified) throws EXistException, PermissionDeniedException {
1340-
1343+
@Override
1344+
public boolean parse(final byte[] xml, final String documentPath, @Nullable String mimeType,
1345+
final int overwrite, @Nullable final Date created, @Nullable final Date modified) throws URISyntaxException, EXistException, PermissionDeniedException {
1346+
final XmldbURI docUri = XmldbURI.xmldbUriFor(documentPath);
13411347
return this.<Boolean>writeCollection(docUri.removeLastSegment()).apply((collection, broker, transaction) -> {
13421348

13431349
try(final ManagedDocumentLock lockedDocument = broker.getBrokerPool().getLockManager().acquireDocumentWriteLock(docUri)) {
@@ -1356,7 +1362,7 @@ private boolean parse(final byte[] xml, final XmldbURI docUri,
13561362

13571363
final long startTime = System.currentTimeMillis();
13581364

1359-
final MimeType mime = MimeTable.getInstance().getContentTypeFor(docUri.lastSegment());
1365+
final MimeType mime = lookupMimeType(mimeType, docUri.lastSegment());
13601366
broker.storeDocument(transaction, docUri.lastSegment(), source, mime, created, modified, null, null, null, collection);
13611367

13621368
// NOTE: early release of Collection lock inline with Asymmetrical Locking scheme
@@ -1369,6 +1375,14 @@ private boolean parse(final byte[] xml, final XmldbURI docUri,
13691375
});
13701376
}
13711377

1378+
private MimeType lookupMimeType(@Nullable final String mimeType, final XmldbURI fileName) {
1379+
final MimeTable mimeTable = MimeTable.getInstance();
1380+
if (mimeType == null) {
1381+
return Optional.ofNullable(mimeTable.getContentTypeFor(fileName)).orElse(MimeType.BINARY_TYPE);
1382+
}
1383+
return Optional.ofNullable(mimeTable.getContentType(mimeType)).orElse(MimeType.BINARY_TYPE);
1384+
}
1385+
13721386
/**
13731387
* Parse a file previously uploaded with upload.
13741388
*
@@ -1482,7 +1496,7 @@ private boolean parseLocal(final String localFile, final XmldbURI docUri, final
14821496

14831497
// parse the source
14841498
try (final FileInputSource source = sourceSupplier.get()) {
1485-
final MimeType mime = Optional.ofNullable(MimeTable.getInstance().getContentType(mimeType)).orElse(MimeType.BINARY_TYPE);
1499+
final MimeType mime = lookupMimeType(mimeType, docUri.lastSegment());
14861500

14871501
broker.storeDocument(transaction, docUri.lastSegment(), source, mime, created, modified, null, null, null, collection);
14881502

0 commit comments

Comments
 (0)