]> git.argeo.org Git - lgpl/argeo-commons.git/blob - server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jcr/JcrResourceAdapter.java
Update versions used
[lgpl/argeo-commons.git] / server / runtime / org.argeo.server.jackrabbit / src / main / java / org / argeo / server / jcr / JcrResourceAdapter.java
1 package org.argeo.server.jcr;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.util.ArrayList;
6 import java.util.Calendar;
7 import java.util.List;
8 import java.util.StringTokenizer;
9
10 import javax.activation.MimetypesFileTypeMap;
11 import javax.jcr.Node;
12 import javax.jcr.Property;
13 import javax.jcr.PropertyIterator;
14 import javax.jcr.Repository;
15 import javax.jcr.RepositoryException;
16 import javax.jcr.Session;
17 import javax.jcr.SimpleCredentials;
18 import javax.jcr.Value;
19 import javax.jcr.version.Version;
20 import javax.jcr.version.VersionHistory;
21 import javax.jcr.version.VersionIterator;
22
23 import org.apache.commons.io.FilenameUtils;
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26 import org.argeo.ArgeoException;
27 import org.springframework.beans.factory.DisposableBean;
28 import org.springframework.beans.factory.InitializingBean;
29 import org.springframework.core.io.Resource;
30
31 public class JcrResourceAdapter implements InitializingBean, DisposableBean {
32 private final static Log log = LogFactory.getLog(JcrResourceAdapter.class);
33
34 private Repository repository;
35
36 private String username;
37 private String password;
38
39 private Session session;
40
41 private Boolean versioning = true;
42 private String defaultEncoding = "UTF-8";
43
44 // private String restoreBase = "/.restore";
45
46 public void mkdirs(String path) {
47 try {
48 StringTokenizer st = new StringTokenizer(path, "/");
49 StringBuffer current = new StringBuffer("/");
50 Node currentNode = session().getRootNode();
51 while (st.hasMoreTokens()) {
52 String part = st.nextToken();
53 current.append(part).append('/');
54 if (!session().itemExists(current.toString())) {
55 currentNode = currentNode.addNode(part, "nt:folder");
56 if (versioning)
57 currentNode.addMixin("mix:versionable");
58 if (log.isTraceEnabled())
59 log.debug("Added folder " + part + " as " + current);
60 } else {
61 currentNode = (Node) session().getItem(current.toString());
62 }
63 }
64 session().save();
65 } catch (RepositoryException e) {
66 throw new ArgeoException("Cannot mkdirs " + path, e);
67 }
68 }
69
70 public void create(String path, Resource file, String mimeType) {
71 try {
72 create(path, file.getInputStream(), mimeType);
73 } catch (IOException e) {
74 throw new ArgeoException("Cannot read " + file, e);
75 }
76 }
77
78 public void create(String path, InputStream in, String mimeType) {
79 try {
80 if (session().itemExists(path)) {
81 throw new ArgeoException("Node " + path + " already exists.");
82 }
83
84 int index = path.lastIndexOf('/');
85 String parentPath = path.substring(0, index);
86 if (parentPath.equals(""))
87 parentPath = "/";
88 String fileName = path.substring(index + 1);
89 if (!session().itemExists(parentPath))
90 throw new ArgeoException("Parent folder of node " + path
91 + " does not exist: " + parentPath);
92
93 Node folderNode = (Node) session().getItem(parentPath);
94 Node fileNode = folderNode.addNode(fileName, "nt:file");
95
96 Node contentNode = fileNode.addNode("jcr:content", "nt:resource");
97 if (mimeType != null)
98 contentNode.setProperty("jcr:mimeType", mimeType);
99 contentNode.setProperty("jcr:encoding", defaultEncoding);
100 contentNode.setProperty("jcr:data", in);
101 Calendar lastModified = Calendar.getInstance();
102 // lastModified.setTimeInMillis(file.lastModified());
103 contentNode.setProperty("jcr:lastModified", lastModified);
104 // resNode.addMixin("mix:referenceable");
105
106 if (versioning)
107 fileNode.addMixin("mix:versionable");
108
109 session().save();
110
111 if (versioning)
112 fileNode.checkin();
113
114 if (log.isDebugEnabled())
115 log.debug("Created " + path);
116 } catch (Exception e) {
117 throw new ArgeoException("Cannot create node for " + path, e);
118 }
119
120 }
121
122 public void update(String path, Resource file) {
123 try {
124 update(path, file.getInputStream());
125 } catch (IOException e) {
126 throw new ArgeoException("Cannot read " + file, e);
127 }
128 }
129
130 public void update(String path, InputStream in) {
131 try {
132
133 if (!session().itemExists(path)) {
134 String type = new MimetypesFileTypeMap()
135 .getContentType(FilenameUtils.getName(path));
136 create(path, in, type);
137 return;
138 }
139
140 Node fileNode = (Node) session().getItem(path);
141 Node contentNode = fileNode.getNode("jcr:content");
142 fileNode.checkout();
143 contentNode.setProperty("jcr:data", in);
144 Calendar lastModified = Calendar.getInstance();
145 // lastModified.setTimeInMillis(file.lastModified());
146 contentNode.setProperty("jcr:lastModified", lastModified);
147
148 session().save();
149 fileNode.checkin();
150
151 if (log.isDebugEnabled())
152 log.debug("Updated " + path);
153 } catch (Exception e) {
154 throw new ArgeoException("Cannot update node " + path, e);
155 }
156 }
157
158 public List<Calendar> listVersions(String path) {
159 if (!versioning)
160 throw new ArgeoException("Versioning is not activated");
161
162 try {
163 List<Calendar> versions = new ArrayList<Calendar>();
164 Node fileNode = (Node) session().getItem(path);
165 VersionHistory history = fileNode.getVersionHistory();
166 for (VersionIterator it = history.getAllVersions(); it.hasNext();) {
167 Version version = (Version) it.next();
168 versions.add(version.getCreated());
169 if (log.isTraceEnabled()) {
170 log.debug(version);
171 // debug(version);
172 }
173 }
174 return versions;
175 } catch (Exception e) {
176 throw new ArgeoException("Cannot list version of node " + path, e);
177 }
178 }
179
180 public InputStream retrieve(String path) {
181 try {
182 Node node = (Node) session().getItem(path + "/jcr:content");
183 Property property = node.getProperty("jcr:data");
184 return property.getStream();
185 } catch (Exception e) {
186 throw new ArgeoException("Cannot retrieve " + path, e);
187 }
188 }
189
190 public synchronized InputStream retrieve(String path, Integer revision) {
191 if (!versioning)
192 throw new ArgeoException("Versioning is not activated");
193
194 try {
195 Node fileNode = (Node) session().getItem(path);
196
197 // if (revision == 0) {
198 // InputStream in = fromVersion(fileNode.getBaseVersion());
199 // if (log.isDebugEnabled())
200 // log.debug("Retrieved " + path + " at base revision ");
201 // return in;
202 // }
203
204 VersionHistory history = fileNode.getVersionHistory();
205 int count = 0;
206 Version version = null;
207 for (VersionIterator it = history.getAllVersions(); it.hasNext();) {
208 version = (Version) it.next();
209 if (count == revision + 1) {
210 InputStream in = fromVersion(version);
211 if (log.isDebugEnabled())
212 log.debug("Retrieved " + path + " at revision "
213 + revision);
214 return in;
215 }
216 count++;
217 }
218 } catch (Exception e) {
219 throw new ArgeoException("Cannot retrieve version " + revision
220 + " of " + path, e);
221 }
222
223 throw new ArgeoException("Version " + revision
224 + " does not exist for node " + path);
225 }
226
227 protected InputStream fromVersion(Version version)
228 throws RepositoryException {
229 Node frozenNode = version.getNode("jcr:frozenNode");
230 InputStream in = frozenNode.getNode("jcr:content").getProperty(
231 "jcr:data").getStream();
232 return in;
233 }
234
235 // protected InputStream restoreOrGetRevision(Node fileNode, Version
236 // version,
237 // Integer revision) throws RepositoryException {
238 // Node parentFolder = (Node) fileNode
239 // .getAncestor(fileNode.getDepth() - 1);
240 // String restoreFolderPath = restoreBase + parentFolder.getPath();
241 // mkdirs(restoreFolderPath);
242 // String subNodeName = fileNode.getName() + "__" + fill(revision);
243 // Node restoreFolder = (Node) session().getItem(restoreFolderPath);
244 // if (!restoreFolder.hasNode(subNodeName)) {
245 // parentFolder.restore(version, subNodeName, true);
246 // }
247 // return parentFolder.getNode(subNodeName + "/jcr:content").getProperty(
248 // "jcr:data").getStream();
249 // }
250
251 protected Session session() {
252 return session;
253 }
254
255 public void afterPropertiesSet() throws Exception {
256 session = repository.login(new SimpleCredentials(username, password
257 .toCharArray()));
258 }
259
260 public void destroy() throws Exception {
261 session.logout();
262 }
263
264 public void setRepository(Repository repository) {
265 this.repository = repository;
266 }
267
268 public void setUsername(String username) {
269 this.username = username;
270 }
271
272 public void setPassword(String password) {
273 this.password = password;
274 }
275
276 public void setVersioning(Boolean versioning) {
277 this.versioning = versioning;
278 }
279
280 public void setDefaultEncoding(String defaultEncoding) {
281 this.defaultEncoding = defaultEncoding;
282 }
283
284 /** Recursively outputs the contents of the given node. */
285 public static void debug(Node node) throws RepositoryException {
286 // First output the node path
287 log.debug(node.getPath());
288 // Skip the virtual (and large!) jcr:system subtree
289 if (node.getName().equals("jcr:system")) {
290 return;
291 }
292
293 // Then output the properties
294 PropertyIterator properties = node.getProperties();
295 while (properties.hasNext()) {
296 Property property = properties.nextProperty();
297 if (property.getDefinition().isMultiple()) {
298 // A multi-valued property, print all values
299 Value[] values = property.getValues();
300 for (int i = 0; i < values.length; i++) {
301 log.debug(property.getPath() + " = "
302 + values[i].getString());
303 }
304 } else {
305 // A single-valued property
306 log.debug(property.getPath() + " = " + property.getString());
307 }
308 }
309
310 }
311
312 protected String fill(Integer number) {
313 int size = 4;
314 String str = number.toString();
315 for (int i = str.length(); i < size; i++) {
316 str = "0" + str;
317 }
318 return str;
319 }
320 }