1 package org
.argeo
.cms
.acr
.fs
;
3 import java
.io
.IOException
;
4 import java
.nio
.ByteBuffer
;
5 import java
.nio
.charset
.StandardCharsets
;
6 import java
.nio
.file
.Files
;
7 import java
.nio
.file
.Path
;
8 import java
.nio
.file
.attribute
.UserDefinedFileAttributeView
;
9 import java
.util
.Iterator
;
11 import java
.util
.NavigableMap
;
12 import java
.util
.Objects
;
13 import java
.util
.TreeMap
;
14 import java
.util
.stream
.Collectors
;
16 import javax
.xml
.namespace
.QName
;
18 import org
.argeo
.api
.acr
.ArgeoNamespace
;
19 import org
.argeo
.api
.acr
.ContentResourceException
;
20 import org
.argeo
.api
.acr
.NamespaceUtils
;
21 import org
.argeo
.api
.acr
.RuntimeNamespaceContext
;
22 import org
.argeo
.api
.acr
.spi
.ContentProvider
;
23 import org
.argeo
.api
.acr
.spi
.ProvidedContent
;
24 import org
.argeo
.api
.acr
.spi
.ProvidedSession
;
25 import org
.argeo
.cms
.util
.OS
;
27 /** Access a file system as a {@link ContentProvider}. */
28 public class FsContentProvider
implements ContentProvider
{
30 protected String mountPath
;
31 protected Path rootPath
;
33 private NavigableMap
<String
, String
> prefixes
= new TreeMap
<>();
35 private final boolean isNtfs
;
36 private final String XMLNS_
;
38 public FsContentProvider(String mountPath
, Path rootPath
) {
39 Objects
.requireNonNull(mountPath
);
40 Objects
.requireNonNull(rootPath
);
42 this.mountPath
= mountPath
;
43 this.rootPath
= rootPath
;
45 this.isNtfs
= OS
.LOCAL
.isMSWindows();
46 this.XMLNS_
= isNtfs ?
"xmlns%3A" : "xmlns:";
48 // FIXME make it more robust
52 protected FsContentProvider() {
53 this.isNtfs
= OS
.LOCAL
.isMSWindows();
54 this.XMLNS_
= isNtfs ?
"xmlns%3A" : "xmlns:";
57 protected void initNamespaces() {
59 UserDefinedFileAttributeView udfav
= Files
.getFileAttributeView(rootPath
,
60 UserDefinedFileAttributeView
.class);
63 for (String name
: udfav
.list()) {
64 if (name
.startsWith(XMLNS_
)) {
65 ByteBuffer buf
= ByteBuffer
.allocate(udfav
.size(name
));
66 udfav
.read(name
, buf
);
68 String namespace
= StandardCharsets
.UTF_8
.decode(buf
).toString();
69 String prefix
= name
.substring(XMLNS_
.length());
70 prefixes
.put(prefix
, namespace
);
75 addDefaultNamespace(udfav
, ArgeoNamespace
.CR_DEFAULT_PREFIX
, ArgeoNamespace
.CR_NAMESPACE_URI
);
76 addDefaultNamespace(udfav
, "basic", ArgeoNamespace
.CR_NAMESPACE_URI
);
77 addDefaultNamespace(udfav
, "owner", ArgeoNamespace
.CR_NAMESPACE_URI
);
78 addDefaultNamespace(udfav
, "posix", ArgeoNamespace
.CR_NAMESPACE_URI
);
79 } catch (IOException e
) {
80 throw new RuntimeException("Cannot read namespaces from " + rootPath
, e
);
85 protected void addDefaultNamespace(UserDefinedFileAttributeView udfav
, String prefix
, String namespace
)
87 if (!prefixes
.containsKey(prefix
)) {
88 ByteBuffer bb
= ByteBuffer
.wrap(namespace
.getBytes(StandardCharsets
.UTF_8
));
89 udfav
.write(XMLNS_
+ prefix
, bb
);
90 prefixes
.put(prefix
, namespace
);
94 public void registerPrefix(String prefix
, String namespace
) {
95 if (prefixes
.containsKey(prefix
))
96 prefixes
.remove(prefix
);
98 UserDefinedFileAttributeView udfav
= Files
.getFileAttributeView(rootPath
,
99 UserDefinedFileAttributeView
.class);
100 addDefaultNamespace(udfav
, prefix
, namespace
);
101 } catch (IOException e
) {
102 throw new RuntimeException("Cannot register namespace " + prefix
+ " " + namespace
+ " on " + rootPath
, e
);
108 public String
getMountPath() {
112 boolean isMountBase(Path path
) {
114 return Files
.isSameFile(rootPath
, path
);
115 } catch (IOException e
) {
116 throw new ContentResourceException(e
);
121 public ProvidedContent
get(ProvidedSession session
, String relativePath
) {
122 return new FsContent(session
, this, rootPath
.resolve(relativePath
));
126 public boolean exists(ProvidedSession session
, String relativePath
) {
127 return Files
.exists(rootPath
.resolve(relativePath
));
134 * Make sure that the prefixed name is compatible with the underlying file
135 * system for file names/attributes (NTFS does not accept :)
137 String
toFsPrefixedName(QName key
) {
138 return isNtfs ? NamespaceUtils
.toPrefixedName(this, key
).replace(":", "%3A")
139 : NamespaceUtils
.toPrefixedName(this, key
);
143 * PArse a prefixed name which is compatible with the underlying file system for
144 * file names/attributes (NTFS does not accept :)
146 QName
fromFsPrefixedName(String name
) {
147 return isNtfs ? NamespaceUtils
.parsePrefixedName(this, name
.replace("%3A", ":"))
148 : NamespaceUtils
.parsePrefixedName(this, name
);
156 public String
getNamespaceURI(String prefix
) {
157 return NamespaceUtils
.getNamespaceURI((p
) -> prefixes
.get(p
), prefix
);
161 public Iterator
<String
> getPrefixes(String namespaceURI
) {
162 Iterator
<String
> res
= NamespaceUtils
.getPrefixes((ns
) -> prefixes
.entrySet().stream()
163 .filter(e
-> e
.getValue().equals(ns
)).map(Map
.Entry
::getKey
).collect(Collectors
.toUnmodifiableSet()),
165 if (!res
.hasNext()) {
166 String prefix
= RuntimeNamespaceContext
.getNamespaceContext().getPrefix(namespaceURI
);
167 if (prefix
!= null) {
168 registerPrefix(prefix
, namespaceURI
);
169 return getPrefixes(namespaceURI
);
171 throw new IllegalArgumentException("Unknown namespace " + namespaceURI
);