Skip to content

Commit a1ba17f

Browse files
authored
Merge pull request #5093 from line-o/backport/5028
[6.x.x] Handle IllegalStateException in file:directory-list#2
2 parents ec00524 + 8ad2fd5 commit a1ba17f

File tree

3 files changed

+147
-89
lines changed

3 files changed

+147
-89
lines changed

extensions/modules/file/src/main/java/org/exist/xquery/modules/file/DirectoryList.java

Lines changed: 66 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
import java.io.IOException;
2525
import java.nio.file.Files;
2626
import java.nio.file.Path;
27-
import java.nio.file.Paths;
2827
import java.util.Date;
2928

3029
import org.apache.logging.log4j.LogManager;
@@ -34,11 +33,7 @@
3433
import org.exist.dom.QName;
3534
import org.exist.dom.memtree.MemTreeBuilder;
3635
import org.exist.util.FileUtils;
37-
import org.exist.xquery.BasicFunction;
38-
import org.exist.xquery.Cardinality;
39-
import org.exist.xquery.FunctionSignature;
40-
import org.exist.xquery.XPathException;
41-
import org.exist.xquery.XQueryContext;
36+
import org.exist.xquery.*;
4237
import org.exist.xquery.value.DateTimeValue;
4338
import org.exist.xquery.value.FunctionParameterSequenceType;
4439
import org.exist.xquery.value.FunctionReturnSequenceType;
@@ -47,50 +42,56 @@
4742
import org.exist.xquery.value.SequenceType;
4843
import org.exist.xquery.value.Type;
4944

45+
import static org.exist.xquery.modules.file.FileErrorCode.DIRECTORY_NOT_FOUND;
46+
5047
/**
5148
* eXist File Module Extension DirectoryList
52-
*
49+
* <p>
5350
* Enumerate a list of files, including their size and modification time, found
5451
* in a specified directory, using a pattern
5552
*
5653
* @author <a href="mailto:[email protected]">Andrzej Taramina</a>
5754
* @author ljo
58-
* @serial 2009-08-09
5955
* @version 1.2
60-
*
61-
* @see
62-
* org.exist.xquery.BasicFunction#BasicFunction(org.exist.xquery.XQueryContext,
56+
* @serial 2009-08-09
57+
* @see org.exist.xquery.BasicFunction#BasicFunction(org.exist.xquery.XQueryContext,
6358
* org.exist.xquery.FunctionSignature)
6459
*/
6560
public class DirectoryList extends BasicFunction {
6661

67-
private final static Logger logger = LogManager.getLogger(DirectoryList.class);
68-
69-
final static String NAMESPACE_URI = FileModule.NAMESPACE_URI;
70-
final static String PREFIX = FileModule.PREFIX;
71-
72-
public final static FunctionSignature[] signatures
73-
= {
74-
new FunctionSignature(
75-
new QName("directory-list", NAMESPACE_URI, PREFIX),
76-
"List all files, including their file size and modification time, "
77-
+ "found in or below a directory, $directory. Files are located in the server's "
78-
+ "file system, using filename patterns, $pattern. File pattern matching is based "
79-
+ "on code from Apache's Ant, thus following the same conventions. For example:\n\n"
80-
+ "'*.xml' matches any file ending with .xml in the current directory,\n- '**/*.xml' matches files "
81-
+ "in any directory below the specified directory. This method is only available to the DBA role.",
82-
new SequenceType[]{
62+
static final String NAMESPACE_URI = FileModule.NAMESPACE_URI;
63+
static final String PREFIX = FileModule.PREFIX;
64+
public static final FunctionSignature[] signatures = {
65+
new FunctionSignature(
66+
new QName("directory-list", NAMESPACE_URI, PREFIX),
67+
"List all files, including their file size and modification time, "
68+
+ "found in or below a directory, $directory. Files are located in the server's "
69+
+ "file system, using filename patterns, $pattern. File pattern matching is based "
70+
+ "on code from Apache's Ant, thus following the same conventions. For example:\n\n"
71+
+ "'*.xml' matches any file ending with .xml in the current directory,\n- '**/*.xml' matches files "
72+
+ "in any directory below the specified directory. This method is only available to the DBA role.",
73+
new SequenceType[]{
8374
new FunctionParameterSequenceType("path", Type.ITEM,
8475
Cardinality.EXACTLY_ONE, "The base directory path or URI in the file system where the files are located."),
8576
new FunctionParameterSequenceType("pattern", Type.STRING,
8677
Cardinality.ZERO_OR_MORE, "The file name pattern")
87-
},
88-
new FunctionReturnSequenceType(Type.NODE,
89-
Cardinality.ZERO_OR_ONE, "a node fragment that shows all matching "
90-
+ "filenames, including their file size and modification time, and "
91-
+ "the subdirectory they were found in")
92-
)
93-
};
78+
},
79+
new FunctionReturnSequenceType(Type.NODE,
80+
Cardinality.ZERO_OR_ONE, "a node fragment that shows all matching "
81+
+ "filenames, including their file size and modification time, and "
82+
+ "the subdirectory they were found in")
83+
)
84+
};
85+
static final QName FILE_ELEMENT = new QName("file", NAMESPACE_URI, PREFIX);
86+
static final QName LIST_ELEMENT = new QName("list", NAMESPACE_URI, PREFIX);
87+
88+
static final QName DIRECTORY_ATTRIBUTE = new QName("directory", null, null);
89+
static final QName NAME_ATTRIBUTE = new QName("name", null, null);
90+
static final QName SIZE_ATTRIBUTE = new QName("size", null, null);
91+
static final QName HUMAN_SIZE_ATTRIBUTE = new QName("human-size", null, null);
92+
static final QName MODIFIED_ATTRIBUTE = new QName("modified", null, null);
93+
static final QName SUBDIR_ATTRIBUTE = new QName("subdir", null, null);
94+
private static final Logger logger = LogManager.getLogger(DirectoryList.class);
9495

9596
public DirectoryList(final XQueryContext context, final FunctionSignature signature) {
9697
super(context, signature);
@@ -117,11 +118,11 @@ public Sequence eval(final Sequence[] args, final Sequence contextSequence) thro
117118
final MemTreeBuilder builder = context.getDocumentBuilder();
118119

119120
builder.startDocument();
120-
builder.startElement(new QName("list", NAMESPACE_URI, PREFIX), null);
121-
builder.addAttribute(new QName("directory", null, null), baseDir.toString());
121+
builder.startElement(LIST_ELEMENT, null);
122+
builder.addAttribute(DIRECTORY_ATTRIBUTE, baseDir.toString());
122123
try {
123124
final int patternsLen = patterns.getItemCount();
124-
final String includes[] = new String[patternsLen];
125+
final String[] includes = new String[patternsLen];
125126
for (int i = 0; i < patternsLen; i++) {
126127
includes[i] = patterns.itemAt(0).getStringValue();
127128
}
@@ -139,76 +140,52 @@ public Sequence eval(final Sequence[] args, final Sequence contextSequence) thro
139140
logger.debug("Found: {}", file.toAbsolutePath());
140141
}
141142

142-
String relPath = file.toString().substring(baseDir.toString().length() + 1);
143+
final String relPath = file.toString().substring(baseDir.toString().length() + 1);
143144

144-
int lastSeparatorPosition = relPath.lastIndexOf(java.io.File.separatorChar);
145+
builder.startElement(FILE_ELEMENT, null);
146+
builder.addAttribute(NAME_ATTRIBUTE, FileUtils.fileName(file));
145147

146-
String relDir = null;
147-
if (lastSeparatorPosition >= 0) {
148-
relDir = relPath.substring(0, lastSeparatorPosition);
149-
relDir = relDir.replace(java.io.File.separatorChar, '/');
150-
}
151-
152-
builder.startElement(new QName("file", NAMESPACE_URI, PREFIX), null);
153-
154-
builder.addAttribute(new QName("name", null, null), FileUtils.fileName(file));
148+
final long sizeLong = FileUtils.sizeQuietly(file);
149+
builder.addAttribute(SIZE_ATTRIBUTE, Long.toString(sizeLong));
150+
builder.addAttribute(HUMAN_SIZE_ATTRIBUTE, getHumanSize(sizeLong));
155151

156-
Long sizeLong = FileUtils.sizeQuietly(file);
157-
String sizeString = Long.toString(sizeLong);
158-
String humanSize = getHumanSize(sizeLong, sizeString);
152+
builder.addAttribute(MODIFIED_ATTRIBUTE,
153+
new DateTimeValue(this,
154+
new Date(Files.getLastModifiedTime(file).toMillis())).getStringValue());
159155

160-
builder.addAttribute(new QName("size", null, null), sizeString);
161-
builder.addAttribute(new QName("human-size", null, null), humanSize);
162-
builder.addAttribute(new QName("modified", null, null), new DateTimeValue(this, new Date(Files.getLastModifiedTime(file).toMillis())).getStringValue());
163-
164-
if (relDir != null && !relDir.isEmpty()) {
165-
builder.addAttribute(new QName("subdir", null, null), relDir);
156+
final int lastSeparatorPosition = relPath.lastIndexOf(java.io.File.separatorChar);
157+
if (lastSeparatorPosition >= 0) {
158+
final String relDir = relPath.substring(0, lastSeparatorPosition);
159+
if (!relDir.isEmpty()) {
160+
builder.addAttribute(SUBDIR_ATTRIBUTE,
161+
relDir.replace(java.io.File.separatorChar, '/'));
162+
}
166163
}
167164

168165
builder.endElement();
169-
170166
}
171167

172168
builder.endElement();
173169

174170
return (NodeValue) builder.getDocument().getDocumentElement();
175-
} catch (final IOException e) {
176-
throw new XPathException(this, e.getMessage());
171+
} catch (final IOException | IllegalStateException e) {
172+
throw new XPathException(this, DIRECTORY_NOT_FOUND, e.getMessage());
177173
} finally {
178174
context.popDocumentContext();
179175
}
180176
}
181177

182-
private String getHumanSize(final Long sizeLong, final String sizeString) {
183-
String humanSize = "n/a";
184-
int sizeDigits = sizeString.length();
185-
186-
if (sizeDigits < 4) {
187-
humanSize = Long.toString(Math.abs(sizeLong));
188-
189-
} else if (sizeDigits >= 4 && sizeDigits <= 6) {
190-
if (sizeLong < 1024) {
191-
// We don't want 0KB för e.g. 1006 Bytes.
192-
humanSize = Long.toString(Math.abs(sizeLong));
193-
} else {
194-
humanSize = Math.abs(sizeLong / 1024) + "KB";
195-
}
196-
197-
} else if (sizeDigits >= 7 && sizeDigits <= 9) {
198-
if (sizeLong < 1048576) {
199-
humanSize = Math.abs(sizeLong / 1024) + "KB";
200-
} else {
201-
humanSize = Math.abs(sizeLong / (1024 * 1024)) + "MB";
202-
}
203-
204-
} else if (sizeDigits > 9) {
205-
if (sizeLong < 1073741824) {
206-
humanSize = Math.abs((sizeLong / (1024 * 1024))) + "MB";
207-
} else {
208-
humanSize = Math.abs((sizeLong / (1024 * 1024 * 1024))) + "GB";
209-
}
178+
private String getHumanSize(final Long sizeLong) {
179+
if (sizeLong < 1024) {
180+
return Math.abs(sizeLong) + "B";
181+
}
182+
if (sizeLong < 1048576) {
183+
return Math.abs(sizeLong / 1024) + "KB";
184+
}
185+
if (sizeLong < 1073741824) {
186+
return Math.abs((sizeLong / (1024 * 1024))) + "MB";
210187
}
211-
return humanSize;
188+
return Math.abs((sizeLong / (1024 * 1024 * 1024))) + "GB";
212189
}
213190

214191
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* eXist-db Open Source Native XML Database
3+
* Copyright (C) 2001 The eXist-db Authors
4+
*
5+
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.file;
23+
24+
import org.exist.dom.QName;
25+
import org.exist.xquery.ErrorCodes;
26+
27+
class FileErrorCode extends ErrorCodes.ErrorCode {
28+
public static final ErrorCodes.ErrorCode DIRECTORY_NOT_FOUND = new FileErrorCode("DIRECTORY_NOT_FOUND",
29+
"The directory could not be found.");
30+
31+
FileErrorCode(final String code, final String description) {
32+
super(new QName(code, FileModule.NAMESPACE_URI, FileModule.PREFIX), description);
33+
}
34+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
(:
2+
: eXist-db Open Source Native XML Database
3+
: Copyright (C) 2001 The eXist-db Authors
4+
:
5+
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+
xquery version "3.1";
23+
24+
module namespace dirlist="http://exist-db.org/testsuite/modules/file/dirlist";
25+
26+
27+
import module namespace file="http://exist-db.org/xquery/file";
28+
29+
30+
declare namespace test="http://exist-db.org/xquery/xqsuite";
31+
32+
33+
declare
34+
%test:assertError("file:DIRECTORY_NOT_FOUND")
35+
function dirlist:non-existent-error-code() {
36+
file:directory-list("/non/existent", ())
37+
};
38+
39+
declare
40+
%test:assertXPath("contains($result,'basedir /non/existent does not exist.') or contains($result,'basedir \non\existent does not exist.')")
41+
function dirlist:non-existent-error-description() {
42+
try {
43+
file:directory-list("/non/existent", ())
44+
} catch file:DIRECTORY_NOT_FOUND {
45+
$err:description
46+
}
47+
};

0 commit comments

Comments
 (0)