]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.jcr/src/org/argeo/jcr/fs/JcrFileSystemProvider.java
[maven-release-plugin] prepare release argeo-commons-2.1.70
[lgpl/argeo-commons.git] / org.argeo.jcr / src / org / argeo / jcr / fs / JcrFileSystemProvider.java
1 package org.argeo.jcr.fs;
2
3 import java.io.IOException;
4 import java.nio.channels.SeekableByteChannel;
5 import java.nio.file.AccessMode;
6 import java.nio.file.CopyOption;
7 import java.nio.file.DirectoryNotEmptyException;
8 import java.nio.file.DirectoryStream;
9 import java.nio.file.DirectoryStream.Filter;
10 import java.nio.file.FileStore;
11 import java.nio.file.LinkOption;
12 import java.nio.file.NoSuchFileException;
13 import java.nio.file.OpenOption;
14 import java.nio.file.Path;
15 import java.nio.file.attribute.BasicFileAttributes;
16 import java.nio.file.attribute.FileAttribute;
17 import java.nio.file.attribute.FileAttributeView;
18 import java.nio.file.spi.FileSystemProvider;
19 import java.util.Calendar;
20 import java.util.HashMap;
21 import java.util.Map;
22 import java.util.Set;
23
24 import javax.jcr.Node;
25 import javax.jcr.Property;
26 import javax.jcr.PropertyIterator;
27 import javax.jcr.PropertyType;
28 import javax.jcr.RepositoryException;
29 import javax.jcr.Session;
30 import javax.jcr.nodetype.NodeType;
31 import javax.jcr.nodetype.PropertyDefinition;
32
33 import org.apache.commons.io.FileExistsException;
34 import org.argeo.jcr.JcrUtils;
35
36 public abstract class JcrFileSystemProvider extends FileSystemProvider {
37 @Override
38 public SeekableByteChannel newByteChannel(Path path, Set<? extends OpenOption> options, FileAttribute<?>... attrs)
39 throws IOException {
40 try {
41 Node node = toNode(path);
42 if (node == null) {
43 Node parent = toNode(path.getParent());
44 if (parent == null)
45 throw new JcrFsException("No parent directory for " + path);
46 if (parent.getPrimaryNodeType().isNodeType(NodeType.NT_FILE)
47 || parent.getPrimaryNodeType().isNodeType(NodeType.NT_LINKED_FILE))
48 throw new JcrFsException(path + " parent is a file");
49
50 String fileName = path.getFileName().toString();
51 fileName = Text.escapeIllegalJcrChars(fileName);
52 node = parent.addNode(fileName, NodeType.NT_FILE);
53 node.addMixin(NodeType.MIX_CREATED);
54 node.addMixin(NodeType.MIX_LAST_MODIFIED);
55 }
56 if (!node.isNodeType(NodeType.NT_FILE))
57 throw new UnsupportedOperationException(node + " must be a file");
58 return new BinaryChannel(node);
59 } catch (RepositoryException e) {
60 throw new JcrFsException("Cannot read file", e);
61 }
62 }
63
64 @Override
65 public DirectoryStream<Path> newDirectoryStream(Path dir, Filter<? super Path> filter) throws IOException {
66 try {
67 Node base = toNode(dir);
68 return new NodeDirectoryStream((JcrFileSystem) dir.getFileSystem(), base.getNodes(), filter);
69 } catch (RepositoryException e) {
70 throw new JcrFsException("Cannot list directory", e);
71 }
72 }
73
74 @Override
75 public void createDirectory(Path dir, FileAttribute<?>... attrs) throws IOException {
76 try {
77 Node node = toNode(dir);
78 if (node == null) {
79 Node parent = toNode(dir.getParent());
80 if (parent == null)
81 throw new IOException("Parent of " + dir + " does not exist");
82 if (parent.getPrimaryNodeType().isNodeType(NodeType.NT_FILE)
83 || parent.getPrimaryNodeType().isNodeType(NodeType.NT_LINKED_FILE))
84 throw new JcrFsException(dir + " parent is a file");
85 String fileName = dir.getFileName().toString();
86 fileName = Text.escapeIllegalJcrChars(fileName);
87 node = parent.addNode(fileName, NodeType.NT_FOLDER);
88 node.addMixin(NodeType.MIX_CREATED);
89 node.addMixin(NodeType.MIX_LAST_MODIFIED);
90 node.getSession().save();
91 } else {
92 if (!node.getPrimaryNodeType().isNodeType(NodeType.NT_FOLDER))
93 throw new FileExistsException(dir + " exists and is not a directory");
94 }
95 } catch (RepositoryException e) {
96 throw new JcrFsException("Cannot create directory " + dir, e);
97 }
98
99 }
100
101 @Override
102 public void delete(Path path) throws IOException {
103 try {
104 Node node = toNode(path);
105 if (node == null)
106 throw new NoSuchFileException(path + " does not exist");
107 Session session = node.getSession();
108 if (node.getPrimaryNodeType().isNodeType(NodeType.NT_FILE))
109 node.remove();
110 else if (node.getPrimaryNodeType().isNodeType(NodeType.NT_FOLDER)) {
111 if (node.hasNodes())// TODO check only files
112 throw new DirectoryNotEmptyException(path.toString());
113 node.remove();
114 }
115 session.save();
116 } catch (RepositoryException e) {
117 throw new JcrFsException("Cannot delete " + path, e);
118 }
119
120 }
121
122 @Override
123 public void copy(Path source, Path target, CopyOption... options) throws IOException {
124 try {
125 Node sourceNode = toNode(source);
126 Node targetNode = toNode(target);
127 JcrUtils.copy(sourceNode, targetNode);
128 sourceNode.getSession().save();
129 } catch (RepositoryException e) {
130 throw new JcrFsException("Cannot copy from " + source + " to " + target, e);
131 }
132 }
133
134 @Override
135 public void move(Path source, Path target, CopyOption... options) throws IOException {
136 try {
137 Node sourceNode = toNode(source);
138 Session session = sourceNode.getSession();
139 session.move(sourceNode.getPath(), target.toString());
140 session.save();
141 } catch (RepositoryException e) {
142 throw new JcrFsException("Cannot move from " + source + " to " + target, e);
143 }
144 }
145
146 @Override
147 public boolean isSameFile(Path path, Path path2) throws IOException {
148 if (path.getFileSystem() != path2.getFileSystem())
149 return false;
150 boolean equ = path.equals(path2);
151 if (equ)
152 return true;
153 else {
154 try {
155 Node node = toNode(path);
156 Node node2 = toNode(path2);
157 return node.isSame(node2);
158 } catch (RepositoryException e) {
159 throw new JcrFsException("Cannot check whether " + path + " and " + path2 + " are same", e);
160 }
161 }
162
163 }
164
165 @Override
166 public boolean isHidden(Path path) throws IOException {
167 return false;
168 }
169
170 @Override
171 public FileStore getFileStore(Path path) throws IOException {
172 Session session = ((JcrFileSystem) path.getFileSystem()).getSession();
173 return new WorkSpaceFileStore(session.getWorkspace());
174 }
175
176 @Override
177 public void checkAccess(Path path, AccessMode... modes) throws IOException {
178 try {
179 Session session = ((JcrFileSystem) path.getFileSystem()).getSession();
180 if (!session.itemExists(path.toString()))
181 throw new NoSuchFileException(path + " does not exist");
182 // TODO check access via JCR api
183 } catch (RepositoryException e) {
184 throw new JcrFsException("Cannot delete " + path, e);
185 }
186 }
187
188 @Override
189 public <V extends FileAttributeView> V getFileAttributeView(Path path, Class<V> type, LinkOption... options) {
190 throw new UnsupportedOperationException();
191 }
192
193 @SuppressWarnings("unchecked")
194 @Override
195 public <A extends BasicFileAttributes> A readAttributes(Path path, Class<A> type, LinkOption... options)
196 throws IOException {
197 try {
198 // TODO check if assignable
199 Node node = toNode(path);
200 if(node==null) {
201 throw new JcrFsException("JCR node not found for "+path);
202 }
203 return (A) new JcrBasicfileAttributes(node);
204 } catch (RepositoryException e) {
205 throw new JcrFsException("Cannot read basic attributes of " + path, e);
206 }
207 }
208
209 @Override
210 public Map<String, Object> readAttributes(Path path, String attributes, LinkOption... options) throws IOException {
211 try {
212 Node node = toNode(path);
213 String pattern = attributes.replace(',', '|');
214 Map<String, Object> res = new HashMap<String, Object>();
215 PropertyIterator it = node.getProperties(pattern);
216 props: while (it.hasNext()) {
217 Property prop = it.nextProperty();
218 PropertyDefinition pd = prop.getDefinition();
219 if (pd.isMultiple())
220 continue props;
221 int requiredType = pd.getRequiredType();
222 switch (requiredType) {
223 case PropertyType.LONG:
224 res.put(prop.getName(), prop.getLong());
225 break;
226 case PropertyType.DOUBLE:
227 res.put(prop.getName(), prop.getDouble());
228 break;
229 case PropertyType.BOOLEAN:
230 res.put(prop.getName(), prop.getBoolean());
231 break;
232 case PropertyType.DATE:
233 res.put(prop.getName(), prop.getDate());
234 break;
235 case PropertyType.BINARY:
236 byte[] arr = JcrUtils.getBinaryAsBytes(prop);
237 res.put(prop.getName(), arr);
238 break;
239 default:
240 res.put(prop.getName(), prop.getString());
241 }
242 }
243 return res;
244 } catch (RepositoryException e) {
245 throw new JcrFsException("Cannot read attributes of " + path, e);
246 }
247 }
248
249 @Override
250 public void setAttribute(Path path, String attribute, Object value, LinkOption... options) throws IOException {
251 try {
252 Node node = toNode(path);
253 if (value instanceof byte[]) {
254 JcrUtils.setBinaryAsBytes(node, attribute, (byte[]) value);
255 } else if (value instanceof Calendar) {
256 node.setProperty(attribute, (Calendar) value);
257 } else {
258 node.setProperty(attribute, value.toString());
259 }
260 node.getSession().save();
261 } catch (RepositoryException e) {
262 throw new JcrFsException("Cannot set attribute " + attribute + " on " + path, e);
263 }
264 }
265
266 protected Node toNode(Path path) throws RepositoryException {
267 return ((JcrPath) path).getNode();
268 }
269
270 /**
271 * To be overriden in order to support the ~ path, with an implementation
272 * specific concept of user home.
273 *
274 * @return null by default
275 */
276 public Node getUserHome(Session session) {
277 return null;
278 }
279 }