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