Skip to content

Commit 8506e38

Browse files
committed
Initial project structure
0 parents  commit 8506e38

21 files changed

+2294
-0
lines changed

.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
.env
2+
target/
3+
*.class
4+
*.jar
5+
*.xar
6+
.idea/
7+
*.iml
8+
.settings/
9+
.project
10+
.classpath

pom.xml

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<parent>
8+
<groupId>org.exist-db</groupId>
9+
<artifactId>exist-apps-parent</artifactId>
10+
<version>2.0.0</version>
11+
<relativePath/>
12+
</parent>
13+
14+
<groupId>org.exist-db</groupId>
15+
<artifactId>exist-request</artifactId>
16+
<version>1.0.0</version>
17+
18+
<name>EXQuery Request Module</name>
19+
<description>Native EXQuery Request Module for eXist-db, compatible with BaseX's 28-function API</description>
20+
<url>https://github.com/joewiz/exist-request</url>
21+
22+
<organization>
23+
<name>The eXist-db Authors</name>
24+
<url>https://exist-db.org</url>
25+
</organization>
26+
27+
<licenses>
28+
<license>
29+
<name>GNU Lesser General Public License, version 2.1</name>
30+
<url>https://opensource.org/licenses/LGPL-2.1</url>
31+
</license>
32+
</licenses>
33+
34+
<scm>
35+
<url>https://github.com/joewiz/exist-request.git</url>
36+
<connection>scm:git:https://github.com/joewiz/exist-request.git</connection>
37+
<developerConnection>scm:git:https://github.com/joewiz/exist-request.git</developerConnection>
38+
</scm>
39+
40+
<properties>
41+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
42+
<project.build.source>21</project.build.source>
43+
<project.build.target>21</project.build.target>
44+
45+
<exist.version>7.0.0-SNAPSHOT</exist.version>
46+
47+
<!-- used in the EXPath Package Descriptor -->
48+
<package-name>http://exist-db.org/apps/request</package-name>
49+
<package-abbrev>request</package-abbrev>
50+
51+
<request.module.namespace>http://exquery.org/ns/request</request.module.namespace>
52+
<request.module.java.classname>org.exist.xquery.modules.request.RequestModule</request.module.java.classname>
53+
</properties>
54+
55+
<dependencies>
56+
<dependency>
57+
<groupId>org.exist-db</groupId>
58+
<artifactId>exist-core</artifactId>
59+
<version>${exist.version}</version>
60+
<scope>provided</scope>
61+
</dependency>
62+
</dependencies>
63+
64+
<profiles>
65+
<profile>
66+
<id>integration-tests</id>
67+
<dependencies>
68+
<dependency>
69+
<groupId>org.exist-db</groupId>
70+
<artifactId>exist-core</artifactId>
71+
<version>${exist.version}</version>
72+
<type>test-jar</type>
73+
<scope>test</scope>
74+
</dependency>
75+
<dependency>
76+
<groupId>org.exist-db</groupId>
77+
<artifactId>exist-start</artifactId>
78+
<version>${exist.version}</version>
79+
<scope>test</scope>
80+
</dependency>
81+
<dependency>
82+
<groupId>junit</groupId>
83+
<artifactId>junit</artifactId>
84+
<version>4.13.2</version>
85+
<scope>test</scope>
86+
</dependency>
87+
</dependencies>
88+
</profile>
89+
</profiles>
90+
91+
<build>
92+
<plugins>
93+
<plugin>
94+
<groupId>ro.kuberam.maven.plugins</groupId>
95+
<artifactId>kuberam-expath-plugin</artifactId>
96+
</plugin>
97+
</plugins>
98+
</build>
99+
100+
<repositories>
101+
<repository>
102+
<id>exist-db</id>
103+
<name>eXist-db Releases</name>
104+
<url>https://repo.exist-db.org/repository/exist-db/</url>
105+
<releases>
106+
<enabled>true</enabled>
107+
</releases>
108+
<snapshots>
109+
<enabled>false</enabled>
110+
</snapshots>
111+
</repository>
112+
<repository>
113+
<id>exist-db-snapshots</id>
114+
<name>eXist-db Snapshots</name>
115+
<url>https://repo.exist-db.org/repository/exist-db-snapshots/</url>
116+
<releases>
117+
<enabled>false</enabled>
118+
</releases>
119+
<snapshots>
120+
<enabled>true</enabled>
121+
</snapshots>
122+
</repository>
123+
</repositories>
124+
</project>
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* eXist-db Open Source Native XML Database
3+
* Copyright (C) 2001 The eXist-db Authors
4+
*
5+
* info@exist-db.org
6+
* http://www.exist-db.org
7+
*
8+
* This library is free software; you can redistribute it and/or
9+
* modify it under the terms of the GNU Lesser General Public
10+
* License as published by the Free Software Foundation; either
11+
* version 2.1 of the License, or (at your option) any later version.
12+
*
13+
* This library is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16+
* Lesser General Public License for more details.
17+
*
18+
* You should have received a copy of the GNU Lesser General Public
19+
* License along with this library; if not, write to the Free Software
20+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21+
*/
22+
package org.exist.xquery.modules.request;
23+
24+
import org.exist.http.servlets.RequestWrapper;
25+
import org.exist.xquery.*;
26+
import org.exist.xquery.value.Sequence;
27+
28+
import javax.annotation.Nonnull;
29+
30+
/**
31+
* Base class for all EXQuery Request Module functions.
32+
*
33+
* <p>Retrieves the HTTP request from the XQuery context via
34+
* {@code context.getHttpContext().getRequest()}. Throws XPDY0002
35+
* if no HTTP context is available (e.g., when called outside an HTTP request).</p>
36+
*/
37+
public abstract class AbstractRequestFunction extends BasicFunction {
38+
39+
public AbstractRequestFunction(final XQueryContext context, final FunctionSignature signature) {
40+
super(context, signature);
41+
}
42+
43+
@Override
44+
public final Sequence eval(final Sequence[] args, final Sequence contextSequence)
45+
throws XPathException {
46+
final XQueryContext.HttpContext httpContext = context.getHttpContext();
47+
if (httpContext == null) {
48+
throw new XPathException(this, ErrorCodes.XPDY0002,
49+
"No HTTP request context available. " +
50+
"The request module functions can only be called within an HTTP request.");
51+
}
52+
53+
final RequestWrapper request = httpContext.getRequest();
54+
if (request == null) {
55+
throw new XPathException(this, ErrorCodes.XPDY0002,
56+
"No HTTP request object found in the current XQuery context.");
57+
}
58+
59+
return eval(args, request);
60+
}
61+
62+
/**
63+
* Evaluate the function with the HTTP request.
64+
*
65+
* @param args the arguments to the function
66+
* @param request the HTTP request wrapper
67+
* @return the result of the function
68+
* @throws XPathException an XPath Exception
69+
*/
70+
protected abstract Sequence eval(final Sequence[] args, @Nonnull final RequestWrapper request)
71+
throws XPathException;
72+
}
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
/*
2+
* eXist-db Open Source Native XML Database
3+
* Copyright (C) 2001 The eXist-db Authors
4+
*
5+
* info@exist-db.org
6+
* http://www.exist-db.org
7+
*
8+
* This library is free software; you can redistribute it and/or
9+
* modify it under the terms of the GNU Lesser General Public
10+
* License as published by the Free Software Foundation; either
11+
* version 2.1 of the License, or (at your option) any later version.
12+
*
13+
* This library is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16+
* Lesser General Public License for more details.
17+
*
18+
* You should have received a copy of the GNU Lesser General Public
19+
* License along with this library; if not, write to the Free Software
20+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21+
*/
22+
package org.exist.xquery.modules.request;
23+
24+
import org.exist.http.servlets.RequestWrapper;
25+
import org.exist.xquery.*;
26+
import org.exist.xquery.value.*;
27+
28+
import javax.annotation.Nonnull;
29+
import java.util.Enumeration;
30+
31+
import static org.exist.xquery.FunctionDSL.*;
32+
33+
/**
34+
* Implements request:attribute(), request:attribute-names(),
35+
* request:attribute-map(), and request:set-attribute().
36+
*/
37+
public class AttributeFunctions extends AbstractRequestFunction {
38+
39+
private static final String FS_ATTRIBUTE_NAME = "attribute";
40+
public static final FunctionSignature[] FS_ATTRIBUTE = functionSignatures(
41+
RequestModule.qname(FS_ATTRIBUTE_NAME),
42+
"Returns the value of the named request attribute.",
43+
returnsOptMany(Type.ITEM, "the attribute value, or empty if not found"),
44+
arities(
45+
arity(
46+
param("name", Type.STRING, "the attribute name")
47+
),
48+
arity(
49+
param("name", Type.STRING, "the attribute name"),
50+
param("default", Type.ITEM, "default value if attribute is not present")
51+
)
52+
)
53+
);
54+
55+
private static final String FS_ATTRIBUTE_NAMES_NAME = "attribute-names";
56+
public static final FunctionSignature FS_ATTRIBUTE_NAMES = functionSignature(
57+
RequestModule.qname(FS_ATTRIBUTE_NAMES_NAME),
58+
"Returns the names of all request attributes.",
59+
returnsOptMany(Type.STRING, "the attribute names")
60+
);
61+
62+
private static final String FS_ATTRIBUTE_MAP_NAME = "attribute-map";
63+
public static final FunctionSignature FS_ATTRIBUTE_MAP = functionSignature(
64+
RequestModule.qname(FS_ATTRIBUTE_MAP_NAME),
65+
"Returns all request attributes as a map.",
66+
returns(Type.MAP, "a map of attribute names to values")
67+
);
68+
69+
private static final String FS_SET_ATTRIBUTE_NAME = "set-attribute";
70+
public static final FunctionSignature FS_SET_ATTRIBUTE = functionSignature(
71+
RequestModule.qname(FS_SET_ATTRIBUTE_NAME),
72+
"Sets a request attribute. Returns the empty sequence.",
73+
returns(Type.EMPTY_SEQUENCE, "empty sequence"),
74+
params(
75+
param("name", Type.STRING, "the attribute name"),
76+
param("value", Type.ITEM, "the attribute value")
77+
)
78+
);
79+
80+
public AttributeFunctions(final XQueryContext context, final FunctionSignature signature) {
81+
super(context, signature);
82+
}
83+
84+
@Override
85+
protected Sequence eval(final Sequence[] args, @Nonnull final RequestWrapper request)
86+
throws XPathException {
87+
if (isCalledAs(FS_ATTRIBUTE_NAME)) {
88+
return getAttribute(args, request);
89+
90+
} else if (isCalledAs(FS_ATTRIBUTE_NAMES_NAME)) {
91+
return getAttributeNames(request);
92+
93+
} else if (isCalledAs(FS_ATTRIBUTE_MAP_NAME)) {
94+
return getAttributeMap(request);
95+
96+
} else if (isCalledAs(FS_SET_ATTRIBUTE_NAME)) {
97+
return setAttribute(args, request);
98+
99+
} else {
100+
throw new XPathException(this, "Unknown function: " + getSignature());
101+
}
102+
}
103+
104+
private Sequence getAttribute(final Sequence[] args, final RequestWrapper request)
105+
throws XPathException {
106+
final String name = args[0].getStringValue();
107+
final Object value = request.getAttribute(name);
108+
109+
if (value == null) {
110+
if (args.length > 1) {
111+
return args[1];
112+
}
113+
return Sequence.EMPTY_SEQUENCE;
114+
}
115+
116+
return XPathUtil.javaObjectToXPath(value, context, this);
117+
}
118+
119+
private Sequence getAttributeNames(final RequestWrapper request) {
120+
final Enumeration<String> names = request.getAttributeNames();
121+
if (!names.hasMoreElements()) {
122+
return Sequence.EMPTY_SEQUENCE;
123+
}
124+
125+
final ValueSequence result = new ValueSequence();
126+
while (names.hasMoreElements()) {
127+
result.add(new StringValue(this, names.nextElement()));
128+
}
129+
return result;
130+
}
131+
132+
private Sequence getAttributeMap(final RequestWrapper request) throws XPathException {
133+
final MapType map = new MapType(this, context);
134+
final Enumeration<String> names = request.getAttributeNames();
135+
136+
while (names.hasMoreElements()) {
137+
final String name = names.nextElement();
138+
final Object value = request.getAttribute(name);
139+
if (value != null) {
140+
map.add(new StringValue(this, name),
141+
XPathUtil.javaObjectToXPath(value, context, this));
142+
}
143+
}
144+
return map;
145+
}
146+
147+
private Sequence setAttribute(final Sequence[] args, final RequestWrapper request)
148+
throws XPathException {
149+
final String name = args[0].getStringValue();
150+
final Sequence value = args[1];
151+
152+
// Store the XQuery value as a Java object on the request
153+
if (value.isEmpty()) {
154+
request.removeAttribute(name);
155+
} else if (value.getItemCount() == 1) {
156+
request.setAttribute(name, value.getStringValue());
157+
} else {
158+
// Multi-valued: store as string for now (most common use case)
159+
request.setAttribute(name, value.getStringValue());
160+
}
161+
162+
return Sequence.EMPTY_SEQUENCE;
163+
}
164+
}

0 commit comments

Comments
 (0)