]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.cms/src/org/argeo/cms/integration/JcrServlet.java
Use Argeo TP Core v2.1.25 and Argeo TP Extras v2.1.13.
[lgpl/argeo-commons.git] / org.argeo.cms / src / org / argeo / cms / integration / JcrServlet.java
1 package org.argeo.cms.integration;
2
3 import java.io.IOException;
4 import java.net.URLDecoder;
5 import java.nio.charset.StandardCharsets;
6
7 import javax.jcr.Node;
8 import javax.jcr.NodeIterator;
9 import javax.jcr.Property;
10 import javax.jcr.PropertyIterator;
11 import javax.jcr.PropertyType;
12 import javax.jcr.Repository;
13 import javax.jcr.RepositoryException;
14 import javax.jcr.Session;
15 import javax.jcr.Value;
16 import javax.servlet.ServletException;
17 import javax.servlet.http.HttpServlet;
18 import javax.servlet.http.HttpServletRequest;
19 import javax.servlet.http.HttpServletResponse;
20
21 import org.apache.commons.logging.Log;
22 import org.apache.commons.logging.LogFactory;
23 import org.apache.jackrabbit.api.JackrabbitNode;
24 import org.apache.jackrabbit.api.JackrabbitValue;
25 import org.argeo.jcr.JcrUtils;
26
27 import com.google.gson.Gson;
28 import com.google.gson.GsonBuilder;
29 import com.google.gson.stream.JsonWriter;
30
31 /** Canonical access to a JCR repository via web services. */
32 public class JcrServlet extends HttpServlet {
33 private static final long serialVersionUID = 6536175260540484539L;
34
35 private final static String PARAM_VERBOSE = "verbose";
36 private final static String PARAM_DEPTH = "depth";
37 private final static String PARAM_PRETTY = "pretty";
38
39 private final static Log log = LogFactory.getLog(JcrServlet.class);
40
41 private Repository repository;
42 private Integer maxDepth = 8;
43
44 private Gson gson = new GsonBuilder().setPrettyPrinting().create();
45
46 @Override
47 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
48 String path = req.getPathInfo();
49 if (log.isTraceEnabled())
50 log.trace("Data service: " + path);
51 path = URLDecoder.decode(path, StandardCharsets.UTF_8.name());
52 String[] pathTokens = path.split("/");
53 // TODO make it more robust
54
55 String domain = pathTokens[1];
56 String dataWorkspace = "vje_" + domain;
57 String jcrPath = path.substring(domain.length() + 1);
58
59 boolean verbose = req.getParameter(PARAM_VERBOSE) != null && !req.getParameter(PARAM_VERBOSE).equals("false");
60 int depth = 1;
61 if (req.getParameter(PARAM_DEPTH) != null) {
62 depth = Integer.parseInt(req.getParameter(PARAM_DEPTH));
63 if (depth > maxDepth)
64 throw new RuntimeException("Depth " + depth + " is higher than maximum " + maxDepth);
65 }
66 String urlBase = null;
67 if (req.getParameter("html") != null)
68 urlBase = req.getServletPath() + '/' + domain;
69 boolean pretty = req.getParameter(PARAM_PRETTY) != null;
70
71 resp.setContentType("application/json");
72 Session session = null;
73 try {
74 // authentication
75 session = openJcrSession(req, resp, repository, dataWorkspace);
76 if (!session.itemExists(jcrPath))
77 throw new RuntimeException("JCR node " + jcrPath + " does not exist");
78 Node node = session.getNode(jcrPath);
79
80 JsonWriter jsonWriter;
81 if (pretty)
82 jsonWriter = new GsonBuilder().setPrettyPrinting().create().newJsonWriter(resp.getWriter());
83 else
84 jsonWriter = gson.newJsonWriter(resp.getWriter());
85 jsonWriter.beginObject();
86 writeNodeProperties(node, jsonWriter, verbose, urlBase);
87 writeNodeChildren(node, jsonWriter, depth, verbose, urlBase);
88 jsonWriter.endObject();
89 jsonWriter.flush();
90 } catch (RepositoryException e) {
91 resp.setStatus(500);
92 throw new RuntimeException("Cannot process JCR node " + jcrPath, e);
93 } finally {
94 JcrUtils.logoutQuietly(session);
95 }
96 }
97
98 protected Session openJcrSession(HttpServletRequest req, HttpServletResponse resp, Repository repository,
99 String workspace) throws RepositoryException {
100 return repository.login();
101 }
102
103 protected void writeNodeProperties(Node node, JsonWriter jsonWriter, boolean verbose, String urlBase)
104 throws RepositoryException, IOException {
105 String jcrPath = node.getPath();
106 jsonWriter.name("jcr:name");
107 jsonWriter.value(node.getName());
108 jsonWriter.name("jcr:path");
109 jsonWriter.value(jcrPath);
110
111 PropertyIterator pit = node.getProperties();
112 properties: while (pit.hasNext()) {
113 Property property = pit.nextProperty();
114 if (!verbose) {
115 if (property.getName().equals("jcr:primaryType") || property.getName().equals("jcr:mixinTypes")
116 || property.getName().equals("jcr:created") || property.getName().equals("jcr:createdBy")
117 || property.getName().equals("jcr:lastModified")
118 || property.getName().equals("jcr:lastModifiedBy")) {
119 continue properties;// skip
120 }
121 }
122
123 if (property.getType() == PropertyType.BINARY) {
124 if (!(node instanceof JackrabbitNode)) {
125 continue properties;// skip
126 }
127 }
128
129 if (!property.isMultiple()) {
130 jsonWriter.name(property.getName());
131 writePropertyValue(property.getType(), property.getValue(), jsonWriter);
132 } else {
133 jsonWriter.name(property.getName());
134 jsonWriter.beginArray();
135 Value[] values = property.getValues();
136 for (Value value : values) {
137 writePropertyValue(property.getType(), value, jsonWriter);
138 }
139 jsonWriter.endArray();
140 }
141 }
142
143 // meta data
144 if (verbose) {
145 jsonWriter.name("jcr:identifier");
146 jsonWriter.value(node.getIdentifier());
147 }
148 if (urlBase != null) {// TODO make it browsable
149 jsonWriter.name("url");
150 String url = urlBase + jcrPath;
151 jsonWriter.value("<a href='" + url + "?html=true'>" + url + "</a>");
152 }
153 }
154
155 protected void writePropertyValue(int type, Value value, JsonWriter jsonWriter)
156 throws RepositoryException, IOException {
157 if (type == PropertyType.DOUBLE)
158 jsonWriter.value(value.getDouble());
159 else if (type == PropertyType.LONG)
160 jsonWriter.value(value.getLong());
161 else if (type == PropertyType.BINARY) {
162 if (value instanceof JackrabbitValue) {
163 String contentIdentity = ((JackrabbitValue) value).getContentIdentity();
164 jsonWriter.value("SHA256:" + contentIdentity);
165 }
166 } else
167 jsonWriter.value(value.getString());
168 }
169
170 protected void writeNodeChildren(Node node, JsonWriter jsonWriter, int depth, boolean verbose, String urlBase)
171 throws RepositoryException, IOException {
172 if (!node.hasNodes())
173 return;
174 if (depth <= 0)
175 return;
176 NodeIterator nit = node.getNodes();
177 jsonWriter.name("jcr:nodes");
178 jsonWriter.beginArray();
179 while (nit.hasNext()) {
180 Node child = nit.nextNode();
181 jsonWriter.beginObject();
182 writeNodeProperties(child, jsonWriter, verbose, urlBase);
183 writeNodeChildren(child, jsonWriter, depth - 1, verbose, urlBase);
184 jsonWriter.endObject();
185 }
186 jsonWriter.endArray();
187 }
188
189 public void setRepository(Repository repository) {
190 this.repository = repository;
191 }
192
193 public void setMaxDepth(Integer maxDepth) {
194 this.maxDepth = maxDepth;
195 }
196
197 }