001    /*
002     * Copyright 2011 The Kuali Foundation.
003     * 
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     * 
008     * http://www.opensource.org/licenses/ecl2.php
009     * 
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.ole.repository;
017    
018    import org.apache.commons.io.FileUtils;
019    import org.kuali.ole.RepositoryManager;
020    import org.kuali.ole.docstore.DocStoreConstants;
021    import org.kuali.ole.docstore.OleDocStoreException;
022    import org.kuali.ole.docstore.model.enums.DocFormat;
023    import org.kuali.ole.docstore.model.enums.DocType;
024    import org.kuali.ole.docstore.model.xmlpojo.ingest.AdditionalAttributes;
025    import org.kuali.ole.docstore.model.xmlpojo.ingest.RequestDocument;
026    import org.kuali.ole.documenthandler.WorkBibMarcContentHandler;
027    import org.kuali.ole.documenthandler.WorkInstanceOleMLContentHandler;
028    import org.kuali.ole.pojo.OleException;
029    import org.slf4j.Logger;
030    import org.slf4j.LoggerFactory;
031    
032    import javax.jcr.*;
033    import java.io.ByteArrayInputStream;
034    import java.io.File;
035    import java.io.InputStream;
036    import java.util.Calendar;
037    import java.util.Collection;
038    import java.util.Date;
039    import java.util.Iterator;
040    import java.text.DateFormat;
041    import java.text.SimpleDateFormat;
042    
043    import static org.kuali.ole.docstore.process.ProcessParameters.*;
044    
045    /**
046     * Created by IntelliJ IDEA.
047     * User: pvsubrah
048     * Date: 9/11/11
049     * Time: 10:37 AM
050     * To change this template use File | Settings | File Templates.
051     */
052    public class NodeHandler {
053    
054        private static final Logger logger = LoggerFactory.getLogger(NodeHandler.class);
055    
056        public Node initStaticNode(String nodeName, Node parentNode, Session session) throws RepositoryException {
057            Node node;
058            if (!parentNode.hasNode(nodeName)) {
059                synchronized (session) {
060                    node = parentNode.addNode(nodeName, "nt:unstructured");
061                    node.setProperty("nodeType", "folder");
062                    node.addMixin("mix:referenceable");
063                    session.save();
064                }
065            }
066            else {
067                node = parentNode.getNode(nodeName);
068            }
069            return node;
070        }
071    
072        public Node initNonStaticNode(String nodeName, Node parentNode) throws RepositoryException {
073            Node node;
074            node = parentNode.addNode(nodeName, "nt:unstructured");
075            node.setProperty("nodeType", "folder");
076            node.addMixin("mix:referenceable");
077            return node;
078        }
079    
080        public synchronized Node initFileNode(RequestDocument document, String name, Node parentNode, Session session)
081                throws Exception {
082            DocStoreConstants docStoreConstants = new DocStoreConstants();
083            String uuid = null;
084            Node fileNode = null;
085            try {
086                NodeIterator nodes = parentNode.getNodes(name);
087                if (nodes.getSize() >= BUCKET_SIZE_FILE_NODES) {
088                    if (DocFormat.OLEML.isEqualTo(document.getFormat())) {
089                        throw new RuntimeException("FileNode creation failed as the BUCKET_SIZE[" + BUCKET_SIZE_FILE_NODES
090                                                   + "] is FULL: for the doc: " + document.getFormat() + "\n@ level: "
091                                                   + parentNode.getPath() + "/" + name + "[" + (nodes.getSize() + 1) + "]");
092                    }
093                    else {
094                        parentNode = initLevelNode(parentNode.getName(), parentNode.getParent(), true, session);
095                    }
096                }
097    
098                fileNode = parentNode.addNode(name, "olefile");
099                fileNode.addMixin("mix:referenceable");
100                if (DocType.LICENSE.isEqualTo(document.getType())  ||  docStoreConstants.isVersioningEnabled ) {
101                    fileNode.addMixin("mix:versionable");
102                }
103    
104                AdditionalAttributes additionalAttributes = document.getAdditionalAttributes();
105                if (DocType.LICENSE.isEqualTo(document.getType()) && !DocFormat.ONIXPL.isEqualTo(document.getFormat())) {
106                    String docName = new File(document.getDocumentName()).getName();
107                    additionalAttributes.setAttribute("dateLoaded", Calendar.getInstance().toString());
108                    additionalAttributes.setAttribute("fileName", docName);
109                    additionalAttributes.setAttribute("owner", document.getUser());
110                }
111    
112                if (additionalAttributes != null) {
113                    Collection<String> attributeNames = additionalAttributes.getAttributeNames();
114                    if (attributeNames != null && attributeNames.size() > 0) {
115                        for (Iterator<String> iterator = attributeNames.iterator(); iterator.hasNext(); ) {
116                            String attributeName = iterator.next();
117                            String attributeValue = additionalAttributes.getAttribute(attributeName);
118                            fileNode.setProperty(attributeName, attributeValue);
119                        }
120                    }
121    
122                }
123                else {
124                    fileNode.setProperty("dateEntered", Calendar.getInstance());
125                    fileNode.setProperty("lastUpdated", Calendar.getInstance());
126                }
127    
128                Node resNode = fileNode.addNode("jcr:content", "nt:resource");
129                resNode.setProperty("jcr:mimeType", "application/xml");
130                resNode.setProperty("jcr:encoding", "");
131    
132                String charset = "UTF-8";
133                byte[] documentBytes = null;
134                try {
135                    uuid = fileNode.getIdentifier();
136                    document.setUuid(uuid);
137                    // Content Manipulations
138                    if (DocFormat.MARC.isEqualTo(document.getFormat())) {
139                        new WorkBibMarcContentHandler().doPreIngestContentManipulations(document, uuid);
140                    }
141                    else if (DocFormat.OLEML.isEqualTo(document.getFormat())) {
142                        (new WorkInstanceOleMLContentHandler())
143                                .doInstanceOleMLContentManipulations(document, uuid, parentNode);
144                    }
145    
146                    if (document.getContent() != null && document.getContent().getContent() != null) {
147                        documentBytes = document.getContent().getContent().getBytes();
148                    }
149    
150                    else if (document.getDocumentName() != null) {
151                        File file = new File(document.getDocumentName());
152                        if (file.exists()) {
153                            documentBytes = FileUtils.readFileToByteArray(file);
154                        }
155                    }
156                }
157                catch (Exception e) {
158                    logger.error("Failed to convert document string to byte[] with charset " + charset, e);
159                }
160                InputStream docInputStream = new ByteArrayInputStream(documentBytes);
161                Binary binary = session.getValueFactory().createBinary(docInputStream);
162                resNode.setProperty("jcr:data", binary);
163                Calendar lastModified = Calendar.getInstance();
164                lastModified.setTimeInMillis(new Date().getTime());
165                resNode.setProperty("jcr:lastModified", lastModified);
166                logger.debug(fileNode.getPath() + " : " + uuid);
167            }
168            catch (RepositoryException e) {
169                logger.error("File Node Cannot be Created: " + e.getMessage(), e);
170            }
171            return fileNode;
172        }
173    
174        /**
175         * Initializes the given fileNode with info from given requestDocument.
176         *
177         * @param fileNode
178         * @param document
179         * @param name
180         * @param parentNode
181         * @param session
182         * @return
183         * @throws Exception
184         */
185        public synchronized Node initFileNode(Node fileNode, RequestDocument document, String name, Node parentNode,
186                                              Session session) throws Exception {
187            String uuid = null;
188            //Node fileNode = null;
189            DocStoreConstants docStoreConstants = new DocStoreConstants();
190            try {
191                /*NodeIterator nodes = parentNode.getNodes(name);
192                if (nodes.getSize() >= BUCKET_SIZE_FILE_NODES) {
193                    if (DocFormat.OLEML.isEqualTo(document.getFormat()))
194                        throw new RuntimeException("FileNode creation failed as the BUCKET_SIZE[" + BUCKET_SIZE_FILE_NODES + "] is FULL: for the doc: "
195                                + document.getFormat() + "\n@ level: " + parentNode.getPath() + "/" + name + "[" + (nodes.getSize() + 1) + "]");
196                    else
197                        parentNode = initLevelNode(parentNode.getName(), parentNode.getParent(), true, session);
198                }
199    
200                fileNode = parentNode.addNode(name, "olefile"); */
201                DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss:SSS");
202                Date date = new Date();
203                //logger.info("NODE INIT: STARTING TIME \t" + dateFormat.format(date));
204                fileNode.addMixin("mix:referenceable");
205                if (DocType.LICENSE.isEqualTo(document.getType()) ||  docStoreConstants.isVersioningEnabled) {
206                    fileNode.addMixin("mix:versionable");
207                }
208    
209                AdditionalAttributes additionalAttributes = document.getAdditionalAttributes();
210                if (DocType.LICENSE.isEqualTo(document.getType()) && !DocFormat.ONIXPL.isEqualTo(document.getFormat())) {
211                    String docName = new File(document.getDocumentName()).getName();
212                    additionalAttributes.setAttribute("dateLoaded", Calendar.getInstance().toString());
213                    additionalAttributes.setAttribute("fileName", docName);
214                    additionalAttributes.setAttribute("owner", document.getUser());
215                }
216    
217                if (additionalAttributes != null) {
218                    Collection<String> attributeNames = additionalAttributes.getAttributeNames();
219                    if (attributeNames != null && attributeNames.size() > 0) {
220                        for (Iterator<String> iterator = attributeNames.iterator(); iterator.hasNext(); ) {
221                            String attributeName = iterator.next();
222                            String attributeValue = additionalAttributes.getAttribute(attributeName);
223                            fileNode.setProperty(attributeName, attributeValue);
224                        }
225                    }
226    
227                }
228                else {
229                    fileNode.setProperty("dateEntered", Calendar.getInstance());
230                    fileNode.setProperty("lastUpdated", Calendar.getInstance());
231                }
232    
233                Node resNode = fileNode.addNode("jcr:content", "nt:resource");
234                resNode.setProperty("jcr:mimeType", "application/xml");
235                resNode.setProperty("jcr:encoding", "");
236    
237                String charset = "UTF-8";
238                byte[] documentBytes = null;
239                try {
240                    uuid = fileNode.getIdentifier();
241                    document.setUuid(uuid);
242                    // Content Manipulations
243                    if (DocFormat.MARC.isEqualTo(document.getFormat())) {
244                        new WorkBibMarcContentHandler().doPreIngestContentManipulations(document, uuid);
245                    }
246                    else if (DocFormat.OLEML.isEqualTo(document.getFormat())) {
247                        (new WorkInstanceOleMLContentHandler())
248                                .doInstanceOleMLContentManipulations(document, uuid, parentNode);
249                    }
250    
251                    if (document.getContent() != null && document.getContent().getContent() != null) {
252                        documentBytes = document.getContent().getContent().getBytes();
253                    }
254                    else if (document.getDocumentName() != null) {
255                        File file = new File(document.getDocumentName());
256                        if (file.exists()) {
257                            documentBytes = FileUtils.readFileToByteArray(file);
258                        }
259                    }
260    
261    
262                }
263                catch (Exception e) {
264                    logger.error("Failed to convert document string to byte[] with charset " + charset, e);
265                }
266                InputStream docInputStream = new ByteArrayInputStream(documentBytes);
267                Binary binary = session.getValueFactory().createBinary(docInputStream);
268                resNode.setProperty("jcr:data", binary);
269                Calendar lastModified = Calendar.getInstance();
270                lastModified.setTimeInMillis(new Date().getTime());
271                resNode.setProperty("jcr:lastModified", lastModified);
272                logger.debug(fileNode.getPath() + " : " + uuid);
273                //logger.info("NODE INIT: ENDING TIME \t" + dateFormat.format(date));
274            }
275            catch (RepositoryException e) {
276                logger.error("File Node Cannot be Created: " + e.getMessage(), e);
277            }
278    
279            return fileNode;
280        }
281    
282        public synchronized Node initLevelNode(String name, Node parent, boolean isRecursiveCall, Session session)
283                throws Exception {
284            long existing = 0;
285            try {
286                long bucketSize = BUCKET_SIZES.get(name);
287                boolean hasRepeatedChild = HAS_REPEATED_CHILD.get(name);
288                if (parent.hasNode(name)) {
289                    NodeIterator existingNodes = parent.getNodes(name);
290                    existing = existingNodes.getSize();
291                    if (existing <= bucketSize && !((isRecursiveCall && existing == bucketSize) || (!hasRepeatedChild
292                                                                                                    && existing
293                                                                                                       == bucketSize))) {
294                        if (hasRepeatedChild && !isRecursiveCall) {
295                            existingNodes.skip(existing - 1);
296                            return existingNodes.nextNode();
297                        }
298                        else {
299                            Node levelNode = initNonStaticNode(name, parent);
300                            if (existing == 0) {
301                                session.save();
302                            }
303                            return levelNode;
304                        }
305                    }
306                    else {
307                        if (!STATIC_NODES.contains(parent.getPath())) {
308                            parent = initLevelNode(parent.getName(), parent.getParent(), true, session);
309                            return initNonStaticNode(name, parent);
310                        }
311                        else {
312                            throw new Exception("Node [" + parent.getName() + "/" + name + "[" + (existing + 1)
313                                                + "]] Cannot Be Created. CAUSE: TREE [" + bucketSize + "] FULL ");
314                        }
315                    }
316                }
317                else {
318                    return initNonStaticNode(name, parent);
319                }
320            }
321            catch (Exception e) {
322                try {
323                    logger.error(
324                            "Exception While initializing Node: " + parent.getName() + "/" + name + "[" + (existing + 1)
325                            + "] \t to Parent: " + parent.getName(), e);
326                }
327                catch (RepositoryException e1) {
328                }
329                throw e;
330            }
331        }
332    
333        public Node getNodeByUUID(Session session, String uuid) throws OleException {
334            logger.debug("Started getting node for UUID:" + uuid);
335            boolean isNewSession = false;
336            if (null == session) {
337                isNewSession = true;
338                logger.debug("Initilalizing new session");
339                session = RepositoryManager.getRepositoryManager().getSession("nodeHandler", "getNodeByUUID");
340            }
341            try {
342                return session.getNodeByIdentifier(uuid);
343            }
344            catch (RepositoryException e) {
345                throw new OleException("getNodeByUUID failed", e);
346            }
347            finally {
348                if (isNewSession) {
349                    RepositoryManager.getRepositoryManager().logout(session);
350                }
351            }
352        }
353    
354    }