Skip to content

Commit

Permalink
Merge pull request #4996 from evolvedbinary/hotfix/restxq-circular-im…
Browse files Browse the repository at this point in the history
…ports

Fixes to eXist-db regarding circular imports
  • Loading branch information
reinhapa authored Oct 15, 2023
2 parents a65d0b0 + 78c34d2 commit 6e80c9b
Show file tree
Hide file tree
Showing 19 changed files with 1,371 additions and 235 deletions.
11 changes: 11 additions & 0 deletions exist-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,17 @@
<artifactId>ant</artifactId>
</dependency>

<dependency>
<groupId>org.jgrapht</groupId>
<artifactId>jgrapht-core</artifactId>
<version>1.5.2</version>
</dependency>

<dependency>
<groupId>org.jgrapht</groupId>
<artifactId>jgrapht-opt</artifactId>
<version>1.5.2</version>
</dependency>

<dependency>
<groupId>junit</groupId>
Expand Down
4 changes: 1 addition & 3 deletions exist-core/src/main/java/org/exist/interpreter/Context.java
Original file line number Diff line number Diff line change
Expand Up @@ -760,8 +760,6 @@ public interface Context {
*/
boolean tailRecursiveCall(FunctionSignature signature);

void mapModule(String namespace, XmldbURI uri);

/**
* Import one or more library modules into the function signatures and in-scope variables of the importing module.
*
Expand All @@ -783,7 +781,7 @@ public interface Context {
* XQST0070
* XQST0088
*/
Module[] importModule(@Nullable String namespaceURI, @Nullable String prefix, @Nullable AnyURIValue[] locationHints) throws XPathException;
@Nullable Module[] importModule(@Nullable String namespaceURI, @Nullable String prefix, @Nullable AnyURIValue[] locationHints) throws XPathException;

/**
* Returns the static location mapped to an XQuery source module, if known.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,8 +248,8 @@ public NativeBroker(final BrokerPool pool, final Configuration config) throws EX
this.indexConfiguration = (IndexSpec) config.getProperty(Indexer.PROPERTY_INDEXER_CONFIG);
this.xmlSerializerPool = new XmlSerializerPool(this, config, 5);

pushSubject(pool.getSecurityManager().getSystemSubject());
try {
pushSubject(pool.getSecurityManager().getSystemSubject());
//TODO : refactor so that we can,
//1) customize the different properties (file names, cache settings...)
//2) have a consistent READ-ONLY behaviour (based on *mandatory* files ?)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ private void serializeXML(final Sequence sequence, final int start, final int ho
private void serializeJSON(final Sequence sequence, final long compilationTime, final long executionTime) throws SAXException, XPathException {
// backwards compatibility: if the sequence contains a single element, we assume
// it should be transformed to JSON following the rules of the old JSON writer
if (sequence.hasOne() && Type.subTypeOf(sequence.getItemType(), Type.ELEMENT)) {
serializeXML(sequence, 1, sequence.getItemCount(), false, false, compilationTime, executionTime);
if (sequence.hasOne() && (Type.subTypeOf(sequence.getItemType(), Type.DOCUMENT) || Type.subTypeOf(sequence.getItemType(), Type.ELEMENT))) {
serializeXML(sequence, 1, 1, false, false, compilationTime, executionTime);
} else {
JSONSerializer serializer = new JSONSerializer(broker, outputProperties);
serializer.serialize(sequence, writer);
Expand Down
82 changes: 73 additions & 9 deletions exist-core/src/main/java/org/exist/xquery/ModuleContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
import org.exist.dom.memtree.MemTreeBuilder;
import org.exist.security.Subject;
import org.exist.storage.UpdateListener;
import org.exist.util.Configuration;
import org.exist.util.FileUtils;
import org.exist.xmldb.XmldbURI;
import org.exist.xquery.value.AnyURIValue;
Expand All @@ -49,29 +48,27 @@


/**
* Subclass of {@link org.exist.xquery.XQueryContext} for
* imported modules.
* Subclass of {@link org.exist.xquery.XQueryContext} for imported modules.
*
* @author wolf
* @author <a href="mailto:[email protected]">Adam Retter</a>
*/
public class ModuleContext extends XQueryContext {

private static final Logger LOG = LogManager.getLogger(ModuleContext.class);

private XQueryContext parentContext;
private String modulePrefix;
private String moduleNamespace;
private String modulePrefix;
private final String location;

public ModuleContext(final XQueryContext parentContext, final String modulePrefix, final String moduleNamespace,
final String location) {
public ModuleContext(final XQueryContext parentContext, final String moduleNamespace, final String modulePrefix, final String location) {
super(parentContext != null ? parentContext.db : null,
parentContext != null ? parentContext.getConfiguration() : null,
null,
false);

this.modulePrefix = modulePrefix;
this.moduleNamespace = moduleNamespace;
this.modulePrefix = modulePrefix;
this.location = location;

setParentContext(parentContext);
Expand All @@ -98,6 +95,73 @@ public void setModuleNamespace(final String prefix, final String namespaceURI) {
this.moduleNamespace = namespaceURI;
}

@Override
protected void addModuleVertex(final ModuleVertex moduleVertex) {
getRootContext().addModuleVertex(moduleVertex);
}

protected boolean hasModuleVertex(final ModuleVertex moduleVertex) {
return getRootContext().hasModuleVertex(moduleVertex);
}

@Override
protected void addModuleEdge(final ModuleVertex source, final ModuleVertex sink) {
getRootContext().addModuleEdge(source, sink);
}

@Override
protected boolean hasModulePath(final ModuleVertex source, final ModuleVertex sink) {
return getRootContext().hasModulePath(source, sink);
}

@Override
public @Nullable Module[] importModule(@Nullable String namespaceURI, @Nullable String prefix, @Nullable AnyURIValue[] locationHints) throws XPathException {
final ModuleVertex thisModuleVertex = new ModuleVertex(moduleNamespace, location);

for (final AnyURIValue locationHint : locationHints) {
final ModuleVertex imporedModuleVertex = new ModuleVertex(namespaceURI, locationHint.toString());

if (!hasModuleVertex(imporedModuleVertex)) {
addModuleVertex(imporedModuleVertex);
} else {
// Check if there is already a path from the imported module to this module
if (getXQueryVersion() == 10 && namespaceURI != null && locationHints != null && hasModulePath(imporedModuleVertex, thisModuleVertex)) {
throw new XPathException(ErrorCodes.XQST0093, "Detected cyclic import between modules: " + getModuleNamespace() + " at: " + getLocation() + ", and: " + namespaceURI + " at: " + locationHint.toString());
}
}

if (!hasModuleVertex(thisModuleVertex)) {
// NOTE(AR) may occur when the actual module has a different namespace from that of the `import module namespace`... will later raise an XQST0047 error
addModuleVertex(thisModuleVertex);
}

addModuleEdge(thisModuleVertex, imporedModuleVertex);
}

return super.importModule(namespaceURI, prefix, locationHints);
}

@Override
protected @Nullable Module importModuleFromLocation(final String namespaceURI, @Nullable final String prefix, final AnyURIValue locationHint) throws XPathException {
// guard against self-recursive import - see: https://github.com/eXist-db/exist/issues/3448
if (moduleNamespace.equals(namespaceURI) && location.equals(locationHint.toString())) {
final StringBuilder builder = new StringBuilder("The XQuery Library Module '");
builder.append(namespaceURI);
builder.append("'");
if (locationHint != null) {
builder.append(" at '");
builder.append(location);
builder.append("'");
}
builder.append(" has invalidly attempted to import itself; this will be skipped!");
LOG.warn(builder.toString());

return null;
}

return super.importModuleFromLocation(namespaceURI, prefix, locationHint);
}

@Override
protected void setModulesChanged() {
parentContext.setModulesChanged();
Expand Down Expand Up @@ -176,7 +240,7 @@ public void updateContext(final XQueryContext from) {

@Override
public XQueryContext copyContext() {
final ModuleContext ctx = new ModuleContext(parentContext, modulePrefix, moduleNamespace, location);
final ModuleContext ctx = new ModuleContext(parentContext, moduleNamespace, modulePrefix, location);
copyFields(ctx);
try {
ctx.declareNamespace(modulePrefix, moduleNamespace);
Expand Down
Loading

0 comments on commit 6e80c9b

Please sign in to comment.