29
29
import org .exist .dom .memtree .MemTreeBuilder ;
30
30
import org .exist .security .Subject ;
31
31
import org .exist .storage .UpdateListener ;
32
- import org .exist .util .Configuration ;
33
32
import org .exist .util .FileUtils ;
34
33
import org .exist .xmldb .XmldbURI ;
35
34
import org .exist .xquery .value .AnyURIValue ;
49
48
50
49
51
50
/**
52
- * Subclass of {@link org.exist.xquery.XQueryContext} for
53
- * imported modules.
51
+ * Subclass of {@link org.exist.xquery.XQueryContext} for imported modules.
54
52
*
55
53
* @author wolf
54
+ * @author <a href="mailto:[email protected] ">Adam Retter</a>
56
55
*/
57
56
public class ModuleContext extends XQueryContext {
58
57
59
58
private static final Logger LOG = LogManager .getLogger (ModuleContext .class );
60
59
61
60
private XQueryContext parentContext ;
62
- private String modulePrefix ;
63
61
private String moduleNamespace ;
62
+ private String modulePrefix ;
64
63
private final String location ;
65
64
66
- public ModuleContext (final XQueryContext parentContext , final String modulePrefix , final String moduleNamespace ,
67
- final String location ) {
65
+ public ModuleContext (final XQueryContext parentContext , final String moduleNamespace , final String modulePrefix , final String location ) {
68
66
super (parentContext != null ? parentContext .db : null ,
69
67
parentContext != null ? parentContext .getConfiguration () : null ,
70
68
null ,
71
69
false );
72
-
73
- this .modulePrefix = modulePrefix ;
74
70
this .moduleNamespace = moduleNamespace ;
71
+ this .modulePrefix = modulePrefix ;
75
72
this .location = location ;
76
73
77
74
setParentContext (parentContext );
@@ -98,6 +95,73 @@ public void setModuleNamespace(final String prefix, final String namespaceURI) {
98
95
this .moduleNamespace = namespaceURI ;
99
96
}
100
97
98
+ @ Override
99
+ protected void addModuleVertex (final ModuleVertex moduleVertex ) {
100
+ getRootContext ().addModuleVertex (moduleVertex );
101
+ }
102
+
103
+ protected boolean hasModuleVertex (final ModuleVertex moduleVertex ) {
104
+ return getRootContext ().hasModuleVertex (moduleVertex );
105
+ }
106
+
107
+ @ Override
108
+ protected void addModuleEdge (final ModuleVertex source , final ModuleVertex sink ) {
109
+ getRootContext ().addModuleEdge (source , sink );
110
+ }
111
+
112
+ @ Override
113
+ protected boolean hasModulePath (final ModuleVertex source , final ModuleVertex sink ) {
114
+ return getRootContext ().hasModulePath (source , sink );
115
+ }
116
+
117
+ @ Override
118
+ public @ Nullable Module [] importModule (@ Nullable String namespaceURI , @ Nullable String prefix , @ Nullable AnyURIValue [] locationHints ) throws XPathException {
119
+ final ModuleVertex thisModuleVertex = new ModuleVertex (moduleNamespace , location );
120
+
121
+ for (final AnyURIValue locationHint : locationHints ) {
122
+ final ModuleVertex imporedModuleVertex = new ModuleVertex (namespaceURI , locationHint .toString ());
123
+
124
+ if (!hasModuleVertex (imporedModuleVertex )) {
125
+ addModuleVertex (imporedModuleVertex );
126
+ } else {
127
+ // Check if there is already a path from the imported module to this module
128
+ if (getXQueryVersion () == 10 && namespaceURI != null && locationHints != null && hasModulePath (imporedModuleVertex , thisModuleVertex )) {
129
+ throw new XPathException (ErrorCodes .XQST0093 , "Detected cyclic import between modules: " + getModuleNamespace () + " at: " + getLocation () + ", and: " + namespaceURI + " at: " + locationHint .toString ());
130
+ }
131
+ }
132
+
133
+ if (!hasModuleVertex (thisModuleVertex )) {
134
+ // 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
135
+ addModuleVertex (thisModuleVertex );
136
+ }
137
+
138
+ addModuleEdge (thisModuleVertex , imporedModuleVertex );
139
+ }
140
+
141
+ return super .importModule (namespaceURI , prefix , locationHints );
142
+ }
143
+
144
+ @ Override
145
+ protected @ Nullable Module importModuleFromLocation (final String namespaceURI , @ Nullable final String prefix , final AnyURIValue locationHint ) throws XPathException {
146
+ // guard against self-recursive import - see: https://github.com/eXist-db/exist/issues/3448
147
+ if (moduleNamespace .equals (namespaceURI ) && location .equals (locationHint .toString ())) {
148
+ final StringBuilder builder = new StringBuilder ("The XQuery Library Module '" );
149
+ builder .append (namespaceURI );
150
+ builder .append ("'" );
151
+ if (locationHint != null ) {
152
+ builder .append (" at '" );
153
+ builder .append (location );
154
+ builder .append ("'" );
155
+ }
156
+ builder .append (" has invalidly attempted to import itself; this will be skipped!" );
157
+ LOG .warn (builder .toString ());
158
+
159
+ return null ;
160
+ }
161
+
162
+ return super .importModuleFromLocation (namespaceURI , prefix , locationHint );
163
+ }
164
+
101
165
@ Override
102
166
protected void setModulesChanged () {
103
167
parentContext .setModulesChanged ();
@@ -176,7 +240,7 @@ public void updateContext(final XQueryContext from) {
176
240
177
241
@ Override
178
242
public XQueryContext copyContext () {
179
- final ModuleContext ctx = new ModuleContext (parentContext , modulePrefix , moduleNamespace , location );
243
+ final ModuleContext ctx = new ModuleContext (parentContext , moduleNamespace , modulePrefix , location );
180
244
copyFields (ctx );
181
245
try {
182
246
ctx .declareNamespace (modulePrefix , moduleNamespace );
0 commit comments