1 package org.kuali.ole.docstore.repository;
2
3 import org.apache.commons.io.FileUtils;
4 import org.kuali.ole.RepositoryManager;
5 import org.kuali.ole.docstore.OleDocStoreException;
6 import org.kuali.ole.docstore.model.enums.DocFormat;
7 import org.kuali.ole.docstore.model.xmlpojo.ingest.AdditionalAttributes;
8 import org.kuali.ole.docstore.model.xmlpojo.ingest.RequestDocument;
9 import org.kuali.ole.pojo.OleException;
10 import org.kuali.ole.repository.NodeHandler;
11 import org.slf4j.Logger;
12 import org.slf4j.LoggerFactory;
13
14 import javax.jcr.*;
15 import java.io.*;
16 import java.util.Calendar;
17 import java.util.Collection;
18 import java.util.Date;
19 import java.util.Iterator;
20
21 import static org.kuali.ole.docstore.process.ProcessParameters.*;
22
23
24
25
26
27
28
29
30 public class CustomNodeManager
31 implements NodeManager {
32 private static final Logger logger = LoggerFactory.getLogger(NodeHandler.class);
33 private static CustomNodeManager ourInstance = new CustomNodeManager();
34
35 protected int numLevels = 3;
36
37 public static CustomNodeManager getInstance() {
38 return ourInstance;
39 }
40
41 public CustomNodeManager() {
42 }
43
44 public Node getParentNode(RequestDocument requestDocument, Session session) throws OleDocStoreException {
45 Node levelNode = null;
46 try {
47 Node formatNode = getStaticFormatNode(requestDocument, session);
48 synchronized (this.getClass()) {
49 for (int i = 1; i <= numLevels; i++) {
50 levelNode = initLevelNode("l" + i, formatNode, false, session);
51 formatNode = levelNode;
52 }
53
54
55
56 }
57 }
58 catch (Exception e) {
59 throw new OleDocStoreException(e);
60 }
61 return levelNode;
62 }
63
64
65 @Override
66 public void linkNodes(Node node, Node linkedDocumentNode, Session session) throws OleDocStoreException {
67 }
68
69 public Node getStaticFormatNode(RequestDocument doc, Session session) throws RepositoryException {
70 Node root = session.getRootNode();
71 Node categoryNode = initStaticNode(doc.getCategory(), root, session);
72 Node typeNode = initStaticNode(doc.getType(), categoryNode, session);
73 Node formatNode = initStaticNode(doc.getFormat(), typeNode, session);
74 return formatNode;
75 }
76
77 public Node initStaticNode(String nodeName, Node parentNode, Session session) throws RepositoryException {
78 Node node;
79 if (!parentNode.hasNode(nodeName)) {
80 synchronized (session) {
81 node = parentNode.addNode(nodeName, "nt:unstructured");
82 node.setProperty("nodeType", "folder");
83 node.addMixin("mix:referenceable");
84 session.save();
85 }
86 }
87 else {
88 node = parentNode.getNode(nodeName);
89 }
90 return node;
91 }
92
93 public Node initNonStaticNode(String nodeName, Node parentNode) throws RepositoryException {
94 Node node;
95 node = parentNode.addNode(nodeName, "nt:unstructured");
96 node.setProperty("nodeType", "folder");
97 node.addMixin("mix:referenceable");
98 return node;
99 }
100
101 protected void modifyAdditionalAttributes(AdditionalAttributes additionalAttributes,
102 RequestDocument requestDocument) {
103 }
104
105 public synchronized Node initLevelNode(String name, Node parent, boolean isRecursiveCall, Session session)
106 throws Exception {
107 long existing = 0;
108 try {
109 long bucketSize = BUCKET_SIZES.get(name);
110 boolean hasRepeatedChild = HAS_REPEATED_CHILD.get(name);
111 if (parent.hasNode(name)) {
112 NodeIterator existingNodes = parent.getNodes(name);
113 existing = existingNodes.getSize();
114 if (existing <= bucketSize && !((isRecursiveCall && existing == bucketSize) || (!hasRepeatedChild
115 && existing
116 == bucketSize))) {
117 if (hasRepeatedChild && !isRecursiveCall) {
118 existingNodes.skip(existing - 1);
119 return existingNodes.nextNode();
120 }
121 else {
122 Node levelNode = initNonStaticNode(name, parent);
123 if (existing == 0) {
124 session.save();
125 }
126 return levelNode;
127 }
128 }
129 else {
130 if (!STATIC_NODES.contains(parent.getPath())) {
131 parent = initLevelNode(parent.getName(), parent.getParent(), true, session);
132 return initNonStaticNode(name, parent);
133 }
134 else {
135 throw new Exception("Node [" + parent.getName() + "/" + name + "[" + (existing + 1)
136 + "]] Cannot Be Created. CAUSE: TREE [" + bucketSize + "] FULL ");
137 }
138 }
139 }
140 else {
141 return initNonStaticNode(name, parent);
142 }
143 }
144 catch (Exception e) {
145 try {
146 logger.error(
147 "Exception While initializing Node: " + parent.getName() + "/" + name + "[" + (existing + 1)
148 + "] \t to Parent: " + parent.getName(), e);
149 }
150 catch (RepositoryException e1) {
151 }
152 throw e;
153 }
154 }
155
156 public synchronized Node initFileNode(RequestDocument document, String name, Node parentNode, Session session)
157 throws Exception {
158 String uuid = null;
159 Node fileNode = createFileNode(document, name, parentNode, session);
160
161 return fileNode;
162 }
163
164 public synchronized Node createFileNode(RequestDocument document, String name, Node parentNode, Session session)
165 throws OleDocStoreException {
166 Node fileNode = null;
167 try {
168 NodeIterator nodes = parentNode.getNodes(name);
169 if (nodes.getSize() >= BUCKET_SIZE_FILE_NODES) {
170 if (document != null && DocFormat.OLEML.isEqualTo(document.getFormat())) {
171 throw new RuntimeException("FileNode creation failed as the BUCKET_SIZE[" + BUCKET_SIZE_FILE_NODES
172 + "] is FULL: for the doc: " + document.getFormat() + "\n@ level: "
173 + parentNode.getPath() + "/" + name + "[" + (nodes.getSize() + 1) + "]");
174 }
175 else {
176 parentNode = initLevelNode(parentNode.getName(), parentNode.getParent(), true, session);
177 }
178 }
179
180 fileNode = parentNode.addNode(name, "olefile");
181 fileNode.addMixin("mix:referenceable");
182
183
184
185
186
187
188
189 AdditionalAttributes additionalAttributes = document.getAdditionalAttributes();
190
191
192
193
194
195
196
197
198
199 if (additionalAttributes != null) {
200 Collection<String> attributeNames = additionalAttributes.getAttributeNames();
201 if (attributeNames != null && attributeNames.size() > 0) {
202 for (Iterator<String> iterator = attributeNames.iterator(); iterator.hasNext(); ) {
203 String attributeName = iterator.next();
204 String attributeValue = additionalAttributes.getAttribute(attributeName);
205 fileNode.setProperty(attributeName, attributeValue);
206 }
207 }
208
209 }
210 else {
211 fileNode.setProperty("dateEntered", Calendar.getInstance());
212 fileNode.setProperty("lastUpdated", Calendar.getInstance());
213 }
214 if (document != null) {
215 document.setUuid(fileNode.getIdentifier());
216 }
217 }
218 catch (Exception e) {
219 throw new OleDocStoreException("File node cannot be created.", e);
220 }
221 return fileNode;
222 }
223
224 public synchronized Node createContentNode(Node fileNode, RequestDocument document, Node parentNode,
225 Session session) throws OleDocStoreException {
226 Node resNode = null;
227 try {
228
229 resNode = fileNode.addNode("jcr:content", "nt:resource");
230 resNode.setProperty("jcr:mimeType", "application/xml");
231 resNode.setProperty("jcr:encoding", "");
232
233 String charset = "UTF-8";
234 byte[] documentBytes = null;
235 try {
236
237
238
239
240
241
242
243
244
245
246
247
248 if (document.getContent() != null && document.getContent().getContent() != null) {
249 documentBytes = document.getContent().getContent().getBytes();
250 }
251
252 else if (document.getDocumentName() != null) {
253 File file = new File(document.getDocumentName());
254 if (file.exists()) {
255 documentBytes = FileUtils.readFileToByteArray(file);
256 }
257 }
258 }
259 catch (Exception e) {
260 logger.error("Failed to convert document string to byte[] with charset " + charset, e);
261 }
262 InputStream docInputStream = new ByteArrayInputStream(documentBytes);
263 Binary binary = session.getValueFactory().createBinary(docInputStream);
264 resNode.setProperty("jcr:data", binary);
265 Calendar lastModified = Calendar.getInstance();
266 lastModified.setTimeInMillis(new Date().getTime());
267 resNode.setProperty("jcr:lastModified", lastModified);
268 }
269 catch (RepositoryException e) {
270 throw new OleDocStoreException(e);
271 }
272 return resNode;
273 }
274
275 public void enableVersioning(Node node) throws OleDocStoreException {
276 try {
277 node.addMixin("mix:versionable");
278 }
279 catch (Exception e) {
280 throw new OleDocStoreException(e);
281 }
282 }
283
284 public Node getNodeByUUID(Session session, String uuid) throws OleDocStoreException {
285 logger.debug("Started getting node for UUID:" + uuid);
286 try {
287 return session.getNodeByIdentifier(uuid);
288 }
289 catch (RepositoryException e) {
290 throw new OleDocStoreException("getNodeByUUID failed", e);
291 }
292 }
293
294 public String getData(Node nodeByUUID) throws OleDocStoreException, RepositoryException, FileNotFoundException {
295 StringBuffer stringBuffer = new StringBuffer();
296 if (null != nodeByUUID) {
297 Node jcrContent = nodeByUUID.getNode("jcr:content");
298 Binary binary = jcrContent.getProperty("jcr:data").getBinary();
299 InputStream content = binary.getStream();
300
301 Writer writer;
302 try {
303 writer = new StringWriter();
304 char[] buffer = new char[1024];
305 try {
306 Reader reader = new BufferedReader(new InputStreamReader(content, "UTF-8"));
307 int n;
308 while ((n = reader.read(buffer)) != -1) {
309 writer.write(buffer, 0, n);
310 }
311 }
312 finally {
313 stringBuffer.append(writer.toString());
314 content.close();
315 }
316
317 }
318 catch (IOException e) {
319 logger.info("failure during checkOut of ", e);
320 }
321
322 }
323
324 return stringBuffer.toString();
325 }
326
327 public byte[] getBinaryData(Node nodeByUUID) throws RepositoryException, IOException {
328 byte[] bytes = null;
329 if (null != nodeByUUID) {
330 Node jcrContent = nodeByUUID.getNode("jcr:content");
331 Binary binary = jcrContent.getProperty("jcr:data").getBinary();
332 InputStream inputStream = binary.getStream();
333 bytes = getBytesFromInputStream(inputStream);
334 }
335 return bytes;
336 }
337
338 public byte[] getBytesFromInputStream(InputStream is) throws IOException {
339 long length = is.available();
340 if (length > Integer.MAX_VALUE) {
341
342 }
343 byte[] bytes = new byte[(int) length];
344
345 int offset = 0;
346 int numRead = 0;
347 while (offset < bytes.length && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
348 offset += numRead;
349 }
350
351 if (offset < bytes.length) {
352 throw new IOException("Could not completely read file ");
353 }
354
355 is.close();
356 return bytes;
357 }
358
359 }