View Javadoc
1   package org.argeo.jcr.fs;
2   
3   import java.io.IOException;
4   import java.nio.file.FileStore;
5   import java.nio.file.FileSystem;
6   import java.nio.file.Path;
7   import java.nio.file.PathMatcher;
8   import java.nio.file.WatchService;
9   import java.nio.file.attribute.UserPrincipalLookupService;
10  import java.nio.file.spi.FileSystemProvider;
11  import java.util.ArrayList;
12  import java.util.HashSet;
13  import java.util.Iterator;
14  import java.util.List;
15  import java.util.Map;
16  import java.util.Set;
17  import java.util.TreeMap;
18  
19  import javax.jcr.Credentials;
20  import javax.jcr.Node;
21  import javax.jcr.Repository;
22  import javax.jcr.RepositoryException;
23  import javax.jcr.Session;
24  import javax.jcr.nodetype.NodeType;
25  
26  import org.argeo.jcr.Jcr;
27  import org.argeo.jcr.JcrUtils;
28  
29  public class JcrFileSystem extends FileSystem {
30  	private final JcrFileSystemProvider provider;
31  
32  	private final Repository repository;
33  	private Session session;
34  	private WorkspaceFileStore baseFileStore;
35  
36  	private Map<String, WorkspaceFileStore> mounts = new TreeMap<>();
37  
38  	private String userHomePath = null;
39  
40  	@Deprecated
41  	public JcrFileSystem(JcrFileSystemProvider provider, Session session) throws IOException {
42  		super();
43  		this.provider = provider;
44  		baseFileStore = new WorkspaceFileStore(null, session.getWorkspace());
45  		this.session = session;
46  //		Node userHome = provider.getUserHome(session);
47  //		if (userHome != null)
48  //			try {
49  //				userHomePath = userHome.getPath();
50  //			} catch (RepositoryException e) {
51  //				throw new IOException("Cannot retrieve user home path", e);
52  //			}
53  		this.repository = null;
54  	}
55  
56  	public JcrFileSystem(JcrFileSystemProvider provider, Repository repository) throws IOException {
57  		this(provider, repository, null);
58  	}
59  
60  	public JcrFileSystem(JcrFileSystemProvider provider, Repository repository, Credentials credentials)
61  			throws IOException {
62  		super();
63  		this.provider = provider;
64  		this.repository = repository;
65  		try {
66  			this.session = credentials == null ? repository.login() : repository.login(credentials);
67  			baseFileStore = new WorkspaceFileStore(null, session.getWorkspace());
68  			workspaces: for (String workspaceName : baseFileStore.getWorkspace().getAccessibleWorkspaceNames()) {
69  				if (workspaceName.equals(baseFileStore.getWorkspace().getName()))
70  					continue workspaces;// do not mount base
71  				if (workspaceName.equals("security")) {
72  					continue workspaces;// do not mount security workspace
73  					// TODO make it configurable
74  				}
75  				Session mountSession = credentials == null ? repository.login(workspaceName)
76  						: repository.login(credentials, workspaceName);
77  				String mountPath = JcrPath.separator + workspaceName;
78  				mounts.put(mountPath, new WorkspaceFileStore(mountPath, mountSession.getWorkspace()));
79  			}
80  		} catch (RepositoryException e) {
81  			throw new IOException("Cannot initialise file system", e);
82  		}
83  
84  		Node userHome = provider.getUserHome(repository);
85  		if (userHome != null)
86  			try {
87  				userHomePath = toFsPath(userHome);
88  			} catch (RepositoryException e) {
89  				throw new IOException("Cannot retrieve user home path", e);
90  			} finally {
91  				JcrUtils.logoutQuietly(Jcr.session(userHome));
92  			}
93  	}
94  
95  	public String toFsPath(Node node) throws RepositoryException {
96  		return getFileStore(node).toFsPath(node);
97  	}
98  
99  	/** Whether this node should be skipped in directory listings */
100 	public boolean skipNode(Node node) throws RepositoryException {
101 		if (node.isNodeType(NodeType.NT_HIERARCHY_NODE))
102 			return false;
103 		return true;
104 	}
105 
106 	public String getUserHomePath() {
107 		return userHomePath;
108 	}
109 
110 	public WorkspaceFileStore getFileStore(String path) {
111 		WorkspaceFileStore res = baseFileStore;
112 		for (String mountPath : mounts.keySet()) {
113 			if (path.equals(mountPath))
114 				return mounts.get(mountPath);
115 			if (path.startsWith(mountPath + JcrPath.separator)) {
116 				res = mounts.get(mountPath);
117 				// we keep the last one
118 			}
119 		}
120 		assert res != null;
121 		return res;
122 	}
123 
124 	public WorkspaceFileStore getFileStore(Node node) throws RepositoryException {
125 		String workspaceName = node.getSession().getWorkspace().getName();
126 		if (workspaceName.equals(baseFileStore.getWorkspace().getName()))
127 			return baseFileStore;
128 		for (String mountPath : mounts.keySet()) {
129 			WorkspaceFileStore fileStore = mounts.get(mountPath);
130 			if (workspaceName.equals(fileStore.getWorkspace().getName()))
131 				return fileStore;
132 		}
133 		throw new IllegalStateException("No workspace mount found for " + node + " in workspace " + workspaceName);
134 	}
135 
136 	public Iterator<JcrPath> listDirectMounts(Path base) {
137 		String baseStr = base.toString();
138 		Set<JcrPath> res = new HashSet<>();
139 		mounts: for (String mountPath : mounts.keySet()) {
140 			if (mountPath.equals(baseStr))
141 				continue mounts;
142 			if (mountPath.startsWith(baseStr)) {
143 				JcrPath path = new JcrPath(this, mountPath);
144 				Path relPath = base.relativize(path);
145 				if (relPath.getNameCount() == 1)
146 					res.add(path);
147 			}
148 		}
149 		return res.iterator();
150 	}
151 
152 	public WorkspaceFileStore getBaseFileStore() {
153 		return baseFileStore;
154 	}
155 
156 	@Override
157 	public FileSystemProvider provider() {
158 		return provider;
159 	}
160 
161 	@Override
162 	public void close() throws IOException {
163 		JcrUtils.logoutQuietly(session);
164 		for (String mountPath : mounts.keySet()) {
165 			WorkspaceFileStore fileStore = mounts.get(mountPath);
166 			try {
167 				fileStore.close();
168 			} catch (Exception e) {
169 				e.printStackTrace();
170 			}
171 		}
172 	}
173 
174 	@Override
175 	public boolean isOpen() {
176 		return session.isLive();
177 	}
178 
179 	@Override
180 	public boolean isReadOnly() {
181 		return false;
182 	}
183 
184 	@Override
185 	public String getSeparator() {
186 		return JcrPath.separator;
187 	}
188 
189 	@Override
190 	public Iterable<Path> getRootDirectories() {
191 		Set<Path> single = new HashSet<>();
192 		single.add(new JcrPath(this, JcrPath.separator));
193 		return single;
194 	}
195 
196 	@Override
197 	public Iterable<FileStore> getFileStores() {
198 		List<FileStore> stores = new ArrayList<>();
199 		stores.add(baseFileStore);
200 		stores.addAll(mounts.values());
201 		return stores;
202 	}
203 
204 	@Override
205 	public Set<String> supportedFileAttributeViews() {
206 		try {
207 			String[] prefixes = session.getNamespacePrefixes();
208 			Set<String> res = new HashSet<>();
209 			for (String prefix : prefixes)
210 				res.add(prefix);
211 			res.add("basic");
212 			return res;
213 		} catch (RepositoryException e) {
214 			throw new JcrFsException("Cannot get supported file attributes views", e);
215 		}
216 	}
217 
218 	@Override
219 	public Path getPath(String first, String... more) {
220 		StringBuilder sb = new StringBuilder(first);
221 		// TODO Make it more robust
222 		for (String part : more)
223 			sb.append('/').append(part);
224 		return new JcrPath(this, sb.toString());
225 	}
226 
227 	@Override
228 	public PathMatcher getPathMatcher(String syntaxAndPattern) {
229 		throw new UnsupportedOperationException();
230 	}
231 
232 	@Override
233 	public UserPrincipalLookupService getUserPrincipalLookupService() {
234 		throw new UnsupportedOperationException();
235 	}
236 
237 	@Override
238 	public WatchService newWatchService() throws IOException {
239 		throw new UnsupportedOperationException();
240 	}
241 
242 //	public Session getSession() {
243 //		return session;
244 //	}
245 
246 	public Repository getRepository() {
247 		return repository;
248 	}
249 
250 }