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