001package org.kuali.ole.docstore.repository; 002 003import org.apache.commons.io.FileUtils; 004import org.kuali.ole.docstore.OleDocStoreException; 005import org.kuali.ole.docstore.model.enums.DocFormat; 006import org.kuali.ole.docstore.model.xmlpojo.ingest.AdditionalAttributes; 007import org.kuali.ole.docstore.model.xmlpojo.ingest.RequestDocument; 008import org.kuali.ole.repository.NodeHandler; 009import org.slf4j.Logger; 010import org.slf4j.LoggerFactory; 011 012import javax.jcr.*; 013import java.io.*; 014import java.util.Calendar; 015import java.util.Collection; 016import java.util.Date; 017import java.util.Iterator; 018 019import static org.kuali.ole.docstore.process.ProcessParameters.*; 020 021/** 022 * Implements custom way of creating levels and nodes. 023 * 024 * @author tirumalesh.b 025 * @version %I%, %G% 026 * Date: 28/8/12 Time: 6:09 PM 027 */ 028public class CustomNodeManager 029 implements NodeManager { 030 private static final Logger logger = LoggerFactory.getLogger(NodeHandler.class); 031 private static CustomNodeManager ourInstance = new CustomNodeManager(); 032 033 protected int numLevels = 3; 034 035 public static CustomNodeManager getInstance() { 036 return ourInstance; 037 } 038 039 public CustomNodeManager() { 040 } 041 042 public Node getParentNode(RequestDocument requestDocument, Session session) throws OleDocStoreException { 043 Node levelNode = null; 044 try { 045 Node formatNode = getStaticFormatNode(requestDocument, session); 046 synchronized (this.getClass()) { 047 for (int i = 1; i <= numLevels; i++) { 048 levelNode = initLevelNode("l" + i, formatNode, false, session); 049 formatNode = levelNode; 050 } 051 // Node l1 = initLevelNode(NODE_LEVEL1, formatNode, false, session); 052 // Node l2 = initLevelNode(NODE_LEVEL2, l1, false, session); 053 // l3 = initLevelNode(NODE_LEVEL3, l2, false, session); 054 } 055 } catch (Exception e) { 056 throw new OleDocStoreException(e); 057 } 058 return levelNode; 059 } 060 061 062 @Override 063 public void linkNodes(Node node, Node linkedDocumentNode, Session session) throws OleDocStoreException { 064 } 065 066 public Node getStaticFormatNode(RequestDocument doc, Session session) throws RepositoryException { 067 Node root = session.getRootNode(); 068 Node categoryNode = initStaticNode(doc.getCategory(), root, session); 069 Node typeNode = initStaticNode(doc.getType(), categoryNode, session); 070 Node formatNode = initStaticNode(doc.getFormat(), typeNode, session); 071 return formatNode; 072 } 073 074 public Node initStaticNode(String nodeName, Node parentNode, Session session) throws RepositoryException { 075 Node node; 076 if (!parentNode.hasNode(nodeName)) { 077 synchronized (session) { 078 node = parentNode.addNode(nodeName, "nt:unstructured"); 079 node.setProperty("nodeType", "folder"); 080 node.addMixin("mix:referenceable"); 081 session.save(); 082 } 083 } else { 084 node = parentNode.getNode(nodeName); 085 } 086 return node; 087 } 088 089 public Node initNonStaticNode(String nodeName, Node parentNode) throws RepositoryException { 090 Node node; 091 node = parentNode.addNode(nodeName, "nt:unstructured"); 092 node.setProperty("nodeType", "folder"); 093 node.addMixin("mix:referenceable"); 094 return node; 095 } 096 097 protected void modifyAdditionalAttributes(AdditionalAttributes additionalAttributes, 098 RequestDocument requestDocument) { 099 } 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 // Node contentNode = createContentNode(fileNode, document, parentNode, session); 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 // if (isVersioningEnabled()) { 173 // fileNode.addMixin("mix:versionable"); 174 // } 175 // if (DocType.LICENSE.isEqualTo(document.getType())) { 176 // fileNode.addMixin("mix:versionable"); 177 // } 178 179 AdditionalAttributes additionalAttributes = document.getAdditionalAttributes(); 180 // if (DocType.LICENSE.isEqualTo(document.getType()) && !DocFormat.ONIXPL.isEqualTo(document.getFormat())) { 181 // String docName = new File(document.getDocumentName()).getName(); 182 // additionalAttributes.setAttribute("dateLoaded", Calendar.getInstance().toString()); 183 // additionalAttributes.setAttribute("fileName", docName); 184 // additionalAttributes.setAttribute("owner", document.getUser()); 185 // } 186 187 //modifyAdditionalAttributes(additionalAttributes, document); 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 // else { 201 // fileNode.setProperty("dateEntered", Calendar.getInstance()); 202 // fileNode.setProperty("lastUpdated", Calendar.getInstance()); 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 // String uuid = fileNode.getIdentifier(); 227 // document.setUuid(uuid); 228 // Content Manipulations 229 // if (DocFormat.MARC.isEqualTo(document.getFormat())) { 230 // new WorkBibMarcContentHandler().doPreIngestContentManipulations(document, uuid); 231 // } 232 // else if (DocFormat.OLEML.isEqualTo(document.getFormat())) { 233 // WorkInstanceDocumentManager resolver = WorkInstanceDocumentManager.getInstance(); 234 // resolver.modifyDocumentContent(document, fileNode.getIdentifier(), parentNode.getIdentifier()); 235 // .doInstanceOleMLContentManipulations(document, fileNode.getIdentifier(), parentNode); 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 // File is too large 324 } 325 byte[] bytes = new byte[(int) length]; 326 // Read in the bytes 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 // Ensure all the bytes have been read in 333 if (offset < bytes.length) { 334 throw new IOException("Could not completely read file "); 335 } 336 // Close the input stream and return bytes 337 is.close(); 338 return bytes; 339 } 340 341 @Override 342 public void ingestItemRecForInstance(RequestDocument reqDoc, String id, Session session) throws OleDocStoreException { 343 //To change body of implemented methods use File | Settings | File Templates. 344 } 345 346 @Override 347 public String getInstanceData(Node instanceNode) 348 throws RepositoryException, OleDocStoreException, FileNotFoundException { 349 return null; //To change body of implemented methods use File | Settings | File Templates. 350 } 351}