]> git.argeo.org Git - lgpl/argeo-commons.git/blob - server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrResourceAdapter.java
Add JCR MVC
[lgpl/argeo-commons.git] / server / runtime / org.argeo.server.jcr / src / main / java / org / argeo / jcr / JcrResourceAdapter.java
1 /*
2 * Copyright (C) 2010 Mathieu Baudier <mbaudier@argeo.org>
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.argeo.jcr;
18
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.util.ArrayList;
22 import java.util.Calendar;
23 import java.util.List;
24
25 import javax.jcr.Node;
26 import javax.jcr.Property;
27 import javax.jcr.RepositoryException;
28 import javax.jcr.Session;
29 import javax.jcr.version.Version;
30 import javax.jcr.version.VersionHistory;
31 import javax.jcr.version.VersionIterator;
32
33 import org.apache.commons.logging.Log;
34 import org.apache.commons.logging.LogFactory;
35 import org.argeo.ArgeoException;
36 import org.springframework.core.io.Resource;
37
38 /**
39 * Bridge Spring resources and JCR folder / files semantics (nt:folder / nt:file),
40 * supporting versioning as well.
41 */
42 public class JcrResourceAdapter {
43 private final static Log log = LogFactory.getLog(JcrResourceAdapter.class);
44
45 private Session session;
46
47 private Boolean versioning = true;
48 private String defaultEncoding = "UTF-8";
49
50 // private String restoreBase = "/.restore";
51
52 public JcrResourceAdapter() {
53 }
54
55 public JcrResourceAdapter(Session session) {
56 this.session = session;
57 }
58
59 public void mkdirs(String path) {
60 JcrUtils.mkdirs(session(), path, "nt:folder", versioning);
61 }
62
63 public void create(String path, Resource file, String mimeType) {
64 try {
65 create(path, file.getInputStream(), mimeType);
66 } catch (IOException e) {
67 throw new ArgeoException("Cannot read " + file, e);
68 }
69 }
70
71 public void create(String path, InputStream in, String mimeType) {
72 try {
73 if (session().itemExists(path)) {
74 throw new ArgeoException("Node " + path + " already exists.");
75 }
76
77 int index = path.lastIndexOf('/');
78 String parentPath = path.substring(0, index);
79 if (parentPath.equals(""))
80 parentPath = "/";
81 String fileName = path.substring(index + 1);
82 if (!session().itemExists(parentPath))
83 throw new ArgeoException("Parent folder of node " + path
84 + " does not exist: " + parentPath);
85
86 Node folderNode = (Node) session().getItem(parentPath);
87 Node fileNode = folderNode.addNode(fileName, "nt:file");
88
89 Node contentNode = fileNode.addNode("jcr:content", "nt:resource");
90 if (mimeType != null)
91 contentNode.setProperty("jcr:mimeType", mimeType);
92 contentNode.setProperty("jcr:encoding", defaultEncoding);
93 contentNode.setProperty("jcr:data", in);
94 Calendar lastModified = Calendar.getInstance();
95 // lastModified.setTimeInMillis(file.lastModified());
96 contentNode.setProperty("jcr:lastModified", lastModified);
97 // resNode.addMixin("mix:referenceable");
98
99 if (versioning)
100 fileNode.addMixin("mix:versionable");
101
102 session().save();
103
104 if (versioning)
105 fileNode.checkin();
106
107 if (log.isDebugEnabled())
108 log.debug("Created " + path);
109 } catch (Exception e) {
110 throw new ArgeoException("Cannot create node for " + path, e);
111 }
112
113 }
114
115 public void update(String path, Resource file) {
116 try {
117 update(path, file.getInputStream());
118 } catch (IOException e) {
119 throw new ArgeoException("Cannot read " + file, e);
120 }
121 }
122
123 public void update(String path, InputStream in) {
124 try {
125
126 if (!session().itemExists(path)) {
127 String type = null;
128 // FIXME: using javax.activation leads to conflict between Java
129 // 1.5 and 1.6 (since javax.activation was included in Java 1.6)
130 // String type = new MimetypesFileTypeMap()
131 // .getContentType(FilenameUtils.getName(path));
132 create(path, in, type);
133 return;
134 }
135
136 Node fileNode = (Node) session().getItem(path);
137 Node contentNode = fileNode.getNode("jcr:content");
138 if (versioning)
139 fileNode.checkout();
140 contentNode.setProperty("jcr:data", in);
141 Calendar lastModified = Calendar.getInstance();
142 // lastModified.setTimeInMillis(file.lastModified());
143 contentNode.setProperty("jcr:lastModified", lastModified);
144
145 session().save();
146 if (versioning)
147 fileNode.checkin();
148
149 if (log.isDebugEnabled())
150 log.debug("Updated " + path);
151 } catch (Exception e) {
152 throw new ArgeoException("Cannot update node " + path, e);
153 }
154 }
155
156 public List<Calendar> listVersions(String path) {
157 if (!versioning)
158 throw new ArgeoException("Versioning is not activated");
159
160 try {
161 List<Calendar> versions = new ArrayList<Calendar>();
162 Node fileNode = (Node) session().getItem(path);
163 VersionHistory history = fileNode.getVersionHistory();
164 for (VersionIterator it = history.getAllVersions(); it.hasNext();) {
165 Version version = (Version) it.next();
166 versions.add(version.getCreated());
167 if (log.isTraceEnabled()) {
168 log.debug(version);
169 // debug(version);
170 }
171 }
172 return versions;
173 } catch (Exception e) {
174 throw new ArgeoException("Cannot list version of node " + path, e);
175 }
176 }
177
178 public InputStream retrieve(String path) {
179 try {
180 Node node = (Node) session().getItem(path + "/jcr:content");
181 Property property = node.getProperty("jcr:data");
182 return property.getStream();
183 } catch (Exception e) {
184 throw new ArgeoException("Cannot retrieve " + path, e);
185 }
186 }
187
188 public synchronized InputStream retrieve(String path, Integer revision) {
189 if (!versioning)
190 throw new ArgeoException("Versioning is not activated");
191
192 try {
193 Node fileNode = (Node) session().getItem(path);
194 VersionHistory history = fileNode.getVersionHistory();
195 int count = 0;
196 Version version = null;
197 for (VersionIterator it = history.getAllVersions(); it.hasNext();) {
198 version = (Version) it.next();
199 if (count == revision + 1) {
200 InputStream in = fromVersion(version);
201 if (log.isDebugEnabled())
202 log.debug("Retrieved " + path + " at revision "
203 + revision);
204 return in;
205 }
206 count++;
207 }
208 } catch (Exception e) {
209 throw new ArgeoException("Cannot retrieve version " + revision
210 + " of " + path, e);
211 }
212
213 throw new ArgeoException("Version " + revision
214 + " does not exist for node " + path);
215 }
216
217 protected InputStream fromVersion(Version version)
218 throws RepositoryException {
219 Node frozenNode = version.getNode("jcr:frozenNode");
220 InputStream in = frozenNode.getNode("jcr:content")
221 .getProperty("jcr:data").getStream();
222 return in;
223 }
224
225 protected Session session() {
226 return session;
227 }
228
229 public void setVersioning(Boolean versioning) {
230 this.versioning = versioning;
231 }
232
233 public void setDefaultEncoding(String defaultEncoding) {
234 this.defaultEncoding = defaultEncoding;
235 }
236
237 protected String fill(Integer number) {
238 int size = 4;
239 String str = number.toString();
240 for (int i = str.length(); i < size; i++) {
241 str = "0" + str;
242 }
243 return str;
244 }
245
246 public void setSession(Session session) {
247 this.session = session;
248 }
249
250 }