• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

evolvedbinary / elemental / 982

29 Apr 2025 08:34PM UTC coverage: 56.409% (+0.007%) from 56.402%
982

push

circleci

adamretter
[feature] Improve README.md badges

28451 of 55847 branches covered (50.94%)

Branch coverage included in aggregate %.

77468 of 131924 relevant lines covered (58.72%)

0.59 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

48.04
/exist-core/src/main/java/org/exist/xquery/functions/util/ModuleInfo.java
1
/*
2
 * Elemental
3
 * Copyright (C) 2024, Evolved Binary Ltd
4
 *
5
 * admin@evolvedbinary.com
6
 * https://www.evolvedbinary.com | https://www.elemental.xyz
7
 *
8
 * Use of this software is governed by the Business Source License 1.1
9
 * included in the LICENSE file and at www.mariadb.com/bsl11.
10
 *
11
 * Change Date: 2028-04-27
12
 *
13
 * On the date above, in accordance with the Business Source License, use
14
 * of this software will be governed by the Apache License, Version 2.0.
15
 *
16
 * Additional Use Grant: Production use of the Licensed Work for a permitted
17
 * purpose. A Permitted Purpose is any purpose other than a Competing Use.
18
 * A Competing Use means making the Software available to others in a commercial
19
 * product or service that: substitutes for the Software; substitutes for any
20
 * other product or service we offer using the Software that exists as of the
21
 * date we make the Software available; or offers the same or substantially
22
 * similar functionality as the Software.
23
 *
24
 * NOTE: Parts of this file contain code from 'The eXist-db Authors'.
25
 *       The original license header is included below.
26
 *
27
 * =====================================================================
28
 *
29
 * eXist-db Open Source Native XML Database
30
 * Copyright (C) 2001 The eXist-db Authors
31
 *
32
 * info@exist-db.org
33
 * http://www.exist-db.org
34
 *
35
 * This library is free software; you can redistribute it and/or
36
 * modify it under the terms of the GNU Lesser General Public
37
 * License as published by the Free Software Foundation; either
38
 * version 2.1 of the License, or (at your option) any later version.
39
 *
40
 * This library is distributed in the hope that it will be useful,
41
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
42
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
43
 * Lesser General Public License for more details.
44
 *
45
 * You should have received a copy of the GNU Lesser General Public
46
 * License along with this library; if not, write to the Free Software
47
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
48
 */
49
package org.exist.xquery.functions.util;
50

51
import java.net.URI;
52
import java.util.Iterator;
53
import java.util.Map;
54

55
import org.apache.logging.log4j.LogManager;
56
import org.apache.logging.log4j.Logger;
57
import org.exist.dom.QName;
58
import org.exist.dom.memtree.MemTreeBuilder;
59
import org.exist.source.Source;
60
import org.exist.xquery.BasicFunction;
61
import org.exist.xquery.Cardinality;
62
import org.exist.xquery.ExternalModule;
63
import org.exist.xquery.FunctionSignature;
64
import org.exist.xquery.Module;
65
import org.exist.xquery.XPathException;
66
import org.exist.xquery.XQueryContext;
67
import org.exist.xquery.value.BooleanValue;
68
import org.exist.xquery.value.FunctionParameterSequenceType;
69
import org.exist.xquery.value.FunctionReturnSequenceType;
70
import org.exist.xquery.value.Sequence;
71
import org.exist.xquery.value.SequenceType;
72
import org.exist.xquery.value.StringValue;
73
import org.exist.xquery.value.Type;
74
import org.exist.xquery.value.ValueSequence;
75

76
import javax.annotation.Nullable;
77
import javax.xml.XMLConstants;
78

79
/**
80
 * @author wolf
81
 */
82
public class ModuleInfo extends BasicFunction {
83
        
84
        protected static final FunctionParameterSequenceType NAMESPACE_URI_PARAMETER = new FunctionParameterSequenceType("namespace-uri", Type.STRING, Cardinality.EXACTLY_ONE, "The namespace URI of the module");
1✔
85
        protected static final FunctionParameterSequenceType LOCATION_URI_PARAMETER = new FunctionParameterSequenceType("location-uri", Type.STRING, Cardinality.EXACTLY_ONE, "The location URI of the module");
1✔
86

87
        protected static final Logger logger = LogManager.getLogger(ModuleInfo.class);
1✔
88

89
        public final static FunctionSignature registeredModulesSig =
1✔
90
                new FunctionSignature(
1✔
91
                        new QName("registered-modules", UtilModule.NAMESPACE_URI, UtilModule.PREFIX),
1✔
92
                        "Returns a sequence containing the namespace URIs of all modules " +
1✔
93
                        "currently known to the system, including built in and imported modules.",
94
                        null,
1✔
95
                        new FunctionReturnSequenceType(Type.STRING, Cardinality.ONE_OR_MORE, "the sequence of all of the active function modules namespace URIs"));
1✔
96
        
97
        public final static FunctionSignature registeredModuleSig =
1✔
98
                new FunctionSignature(
1✔
99
                        new QName("is-module-registered", UtilModule.NAMESPACE_URI, UtilModule.PREFIX),
1✔
100
                        "Returns a Boolean value if the module identified by the namespace URI is registered.",
1✔
101
                        new SequenceType[] { NAMESPACE_URI_PARAMETER },
1✔
102
                        new FunctionReturnSequenceType(Type.BOOLEAN, Cardinality.EXACTLY_ONE, "true if the namespace URI is registered as an active function module"));
1✔
103

104
    public final static FunctionSignature mappedModulesSig =
1✔
105
                new FunctionSignature(
1✔
106
                        new QName("mapped-modules", UtilModule.NAMESPACE_URI, UtilModule.PREFIX),
1✔
107
                        "Returns a sequence containing the namespace URIs of all XQuery modules " +
1✔
108
                        "which are statically mapped to a source location in the configuration file. " +
109
            "This does not include any built in modules.",
110
                        null,
1✔
111
                        new FunctionReturnSequenceType(Type.STRING, Cardinality.ONE_OR_MORE, "the sequence of all of the active function modules namespace URIs"));
1✔
112

113
        public final static FunctionSignature mappedModuleSig =
1✔
114
                new FunctionSignature(
1✔
115
                        new QName("is-module-mapped", UtilModule.NAMESPACE_URI, UtilModule.PREFIX),
1✔
116
                        "Returns a Boolean value if the module statically mapped to a source location in the configuration file.",
1✔
117
                        new SequenceType[] { NAMESPACE_URI_PARAMETER },
1✔
118
                        new FunctionReturnSequenceType(Type.BOOLEAN, Cardinality.EXACTLY_ONE, "true if the namespace URI is mapped as an active function module"));
1✔
119

120
        public final static FunctionSignature mapModuleSig =
1✔
121
                new FunctionSignature(
1✔
122
                        new QName("map-module", UtilModule.NAMESPACE_URI, UtilModule.PREFIX),
1✔
123
                        "Map the module to a source location. This function is only available to the DBA role.",
1✔
124
                        new SequenceType[] { NAMESPACE_URI_PARAMETER, LOCATION_URI_PARAMETER },
1✔
125
                        new FunctionReturnSequenceType( Type.ITEM, Cardinality.EMPTY_SEQUENCE, "Returns an empty sequence" ));
1✔
126

127
        public final static FunctionSignature unmapModuleSig =
1✔
128
                new FunctionSignature(
1✔
129
                        new QName("unmap-module", UtilModule.NAMESPACE_URI, UtilModule.PREFIX),
1✔
130
                        "Remove relation between module namespace and source location. This function is only available to the DBA role.",
1✔
131
                        new SequenceType[] { NAMESPACE_URI_PARAMETER },
1✔
132
                        new FunctionReturnSequenceType( Type.ITEM, Cardinality.EMPTY_SEQUENCE, "Returns an empty sequence" ));
1✔
133

134
        public final static FunctionSignature moduleDescriptionSig =
1✔
135
                new FunctionSignature(
1✔
136
                        new QName("get-module-description", UtilModule.NAMESPACE_URI, UtilModule.PREFIX),
1✔
137
                        "Returns a short description of the module identified by the namespace URI.",
1✔
138
                        new SequenceType[] { NAMESPACE_URI_PARAMETER },
1✔
139
                        new FunctionReturnSequenceType(Type.STRING, Cardinality.ONE_OR_MORE, "the description of the active function module identified by the namespace URI"),
1✔
140
                                "Use inspect:inspect-module-uri#1 instead!"
1✔
141
        );
142
        
143
        public final static FunctionSignature moduleInfoSig =
1✔
144
                new FunctionSignature(
1✔
145
                        new QName("get-module-info", UtilModule.NAMESPACE_URI, UtilModule.PREFIX),
1✔
146
                        "Returns an XML fragment providing additional information about the module identified by the " +
1✔
147
                        "namespace URI.",
148
                        null,
1✔
149
                        new FunctionReturnSequenceType(Type.ELEMENT, Cardinality.EXACTLY_ONE, 
1✔
150
                                        "the description of the active function module identified by the namespace URI")
1✔
151
        );
152
        
153
        public final static FunctionSignature moduleInfoWithURISig =
1✔
154
            new FunctionSignature(
1✔
155
                new QName("get-module-info", UtilModule.NAMESPACE_URI, UtilModule.PREFIX),
1✔
156
                "Returns an XML fragment providing additional information about the module identified by the " +
1✔
157
                "namespace URI.",
158
                new SequenceType[] { NAMESPACE_URI_PARAMETER },
1✔
159
                new FunctionReturnSequenceType(Type.ELEMENT, Cardinality.EXACTLY_ONE, 
1✔
160
                "the description of the active function module identified by the namespace URI"),
1✔
161
                                        "Use inspect:inspect-module-uri#1 instead!"
1✔
162
        );
163
        
164
        private static final QName MODULE_QNAME = new QName("module", XMLConstants.NULL_NS_URI);
1✔
165
        private static final QName MODULE_URI_ATTR = new QName("uri", XMLConstants.NULL_NS_URI);
1✔
166
        private static final QName MODULE_PREFIX_ATTR = new QName("prefix", XMLConstants.NULL_NS_URI);
1✔
167
        private static final QName MODULE_SOURCE_ATTR = new QName("source", XMLConstants.NULL_NS_URI);
1✔
168
        private static final QName MODULE_DESC_QNAME = new QName("description", XMLConstants.NULL_NS_URI);
1✔
169
        private static final QName MODULES_QNAME = new QName("modules", XMLConstants.NULL_NS_URI);
1✔
170

171
        public ModuleInfo(XQueryContext context, FunctionSignature signature) {
172
                super(context, signature);
1✔
173
        }
1✔
174

175
        @Override
176
        public Sequence eval(Sequence[] args, Sequence contextSequence)
177
                        throws XPathException {
178
                
179
                if("get-module-description".equals(getSignature().getName().getLocalPart())) {
1!
180
                        final String uri = args[0].getStringValue();
×
181
                        @Nullable final Module[] modules = context.getModules(uri);
×
182
                        if (modules == null || modules.length == 0) {
×
183
                                throw new XPathException(this, "No module found matching namespace URI: " + uri);
×
184
                        }
185
                        final Sequence result = new ValueSequence();
×
186
                        for (final Module module : modules) {
×
187
                                result.add(new StringValue(this, module.getDescription()));
×
188
                        }
189
                        return result;
×
190
                } else if ("is-module-registered".equals(getSignature().getName().getLocalPart())) {
1!
191
                        final String uri = args[0].getStringValue();
×
192
                        final Module[] modules = context.getModules(uri);
×
193
                        return new BooleanValue(this, modules != null && modules.length > 0);
×
194
        } else if ("mapped-modules".equals(getSignature().getName().getLocalPart())) {
1!
195
            final ValueSequence resultSeq = new ValueSequence();
×
196
            for (final Iterator<String> i = context.getMappedModuleURIs(); i.hasNext();) {
×
197
                resultSeq.add(new StringValue(this, i.next()));
×
198
            }
199
            return resultSeq;
×
200
                } else if ("is-module-mapped".equals(getSignature().getName().getLocalPart())) {
1!
201
                        final String uri = args[0].getStringValue();
×
202
                        return new BooleanValue(this, ((Map<String, String>)context.getBroker().getConfiguration().getProperty(XQueryContext.PROPERTY_STATIC_MODULE_MAP)).get(uri) != null);
×
203
                } else if ("map-module".equals(getSignature().getName().getLocalPart())) {
1!
204
                        if (!context.getSubject().hasDbaRole()) {
×
205
                                final XPathException xPathException = new XPathException(this, "Permission denied, calling user '" + context.getSubject().getName() + "' must be a DBA to call this function.");
×
206
                                logger.error("Invalid user", xPathException);
×
207
                                throw xPathException;
×
208
                        }                        
209
                        final String namespace = args[0].getStringValue();
×
210
                        final String location = args[1].getStringValue();
×
211
                        final Map <String, String> moduleMap = (Map<String, String>)context.getBroker().getConfiguration().getProperty(XQueryContext.PROPERTY_STATIC_MODULE_MAP);
×
212
                        moduleMap.put(namespace, location);
×
213
                        return Sequence.EMPTY_SEQUENCE;
×
214
                } else if ("unmap-module".equals(getSignature().getName().getLocalPart())) {
1!
215
                        if (!context.getSubject().hasDbaRole()) {
×
216
                                final XPathException xPathException = new XPathException(this, "Permission denied, calling user '" + context.getSubject().getName() + "' must be a DBA to call this function.");
×
217
                                logger.error("Invalid user", xPathException);
×
218
                                throw xPathException;
×
219
                        }                        
220
                        final String namespace = args[0].getStringValue();
×
221
                        final Map <String, String> moduleMap = (Map<String, String>)context.getBroker().getConfiguration().getProperty(XQueryContext.PROPERTY_STATIC_MODULE_MAP);
×
222
                        moduleMap.remove(namespace);
×
223
                        return Sequence.EMPTY_SEQUENCE;
×
224
                } else if ("get-module-info".equals(getSignature().getName().getLocalPart())) {
1!
225
                        context.pushDocumentContext();
×
226
                        
227
                        try {
228
                                final MemTreeBuilder builder = context.getDocumentBuilder();
×
229
                                builder.startElement(MODULES_QNAME, null);
×
230
                                
231
                                if (getArgumentCount() == 1) {
×
232
                                        final Module[] modules = context.getModules(args[0].getStringValue());
×
233
                                        if (modules != null) {
×
234
                                                outputModules(builder, modules);
×
235
                                        }
236
                                } else {
×
237
                                        for(final Iterator<Module> i = context.getRootModules(); i.hasNext(); ) {
×
238
                                                final Module module = i.next();
×
239
                                                outputModule(builder, module);
×
240
                                        }
241
                                }
242
                                return builder.getDocument().getNode(1);
×
243
                        } finally {
244
                                context.popDocumentContext();
×
245
                        }
246
                } else {
247
                        final ValueSequence resultSeq = new ValueSequence();
1✔
248
            final XQueryContext tempContext = new XQueryContext(context.getBroker().getBrokerPool());
1✔
249
                        try {
250
                                for (final Iterator<Module> i = tempContext.getRootModules(); i.hasNext(); ) {
1✔
251
                                        final Module module = i.next();
1✔
252
                                        resultSeq.add(new StringValue(this, module.getNamespaceURI()));
1✔
253
                                }
254
                                if (tempContext.getRepository().isPresent()) {
1!
255
                                        for (final URI uri : tempContext.getRepository().get().getJavaModules()) {
1!
256
                                                resultSeq.add(new StringValue(this, uri.toString()));
×
257
                                        }
258
                                }
259
                        } finally {
1✔
260
                                tempContext.reset();
1✔
261
                                tempContext.runCleanupTasks();
1✔
262
                        }
263
                        return resultSeq;
1✔
264
                }
265
        }
266

267
        private void outputModules(final MemTreeBuilder builder, final Module[] modules) {
268
                if (modules == null) {
×
269
                        return;
×
270
                }
271

272
                for (final Module module : modules) {
×
273
                        outputModule(builder, module);
×
274
                }
275
        }
×
276

277
        private void outputModule(final MemTreeBuilder builder, final Module module) {
278
                builder.startElement(MODULE_QNAME, null);
×
279
                
280
                builder.addAttribute(MODULE_URI_ATTR, module.getNamespaceURI());
×
281
                builder.addAttribute(MODULE_PREFIX_ATTR, module.getDefaultPrefix());
×
282
                if (!module.isInternalModule()) {
×
283
                        final Source source = ((ExternalModule)module).getSource();
×
284
                        if (source != null) {
×
285
                                builder.addAttribute(MODULE_SOURCE_ATTR, source.pathOrContentOrShortIdentifier());
×
286
                        }
287
                }
288
                builder.startElement(MODULE_DESC_QNAME, null);
×
289
                builder.characters(module.getDescription());
×
290
                builder.endElement(); // <description>
×
291
                
292
                builder.endElement(); // <module>
×
293
        }
×
294

295
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc