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 */
016package org.kuali.ole.repository;
017
018import org.apache.commons.io.FileUtils;
019import org.kuali.ole.RepositoryManager;
020import org.kuali.ole.docstore.DocStoreConstants;
021import org.kuali.ole.docstore.common.document.content.instance.Item;
022import org.kuali.ole.docstore.common.document.content.instance.OleHoldings;
023import org.kuali.ole.docstore.common.document.content.instance.SourceHoldings;
024import org.kuali.ole.docstore.common.document.content.instance.xstream.HoldingOlemlRecordProcessor;
025import org.kuali.ole.docstore.common.document.content.instance.xstream.ItemOlemlRecordProcessor;
026import org.kuali.ole.docstore.common.document.content.instance.xstream.SourceHoldingOlemlRecordProcessor;
027import org.kuali.ole.docstore.model.enums.DocType;
028import org.kuali.ole.docstore.model.xmlpojo.ingest.RequestDocument;
029import org.kuali.ole.docstore.process.ProcessParameters;
030import org.kuali.ole.docstore.service.DocumentIndexer;
031import org.kuali.ole.docstore.service.ServiceLocator;
032import org.kuali.ole.logger.DocStoreLogger;
033import org.kuali.ole.pojo.OleException;
034import org.slf4j.Logger;
035import org.slf4j.LoggerFactory;
036
037import javax.jcr.Binary;
038import javax.jcr.Node;
039import javax.jcr.RepositoryException;
040import javax.jcr.Session;
041import javax.jcr.version.VersionHistory;
042import javax.jcr.version.VersionIterator;
043import javax.jcr.version.VersionManager;
044import java.io.ByteArrayInputStream;
045import java.io.File;
046import java.util.Calendar;
047import java.util.Iterator;
048
049import static org.kuali.ole.docstore.process.ProcessParameters.FILE_ITEM;
050
051public class CheckinManager {
052
053    DocStoreLogger docStoreLogger = new DocStoreLogger(this.getClass().getName());
054    private static final Logger LOG = LoggerFactory.getLogger(CheckinManager.class);
055
056    public String updateContent(RequestDocument requestDocument) throws OleException {
057        //        List<String> ingestDocs = new ArrayList<String>();
058        //        List<String> uuids = new ArrayList<String>();
059        //        StringBuilder sb = new StringBuilder();
060        //        String uuid = null;
061        String content = null;
062        String latestVersion = null;
063        String checkInFail = "Check in failed. ";
064        content = requestDocument.getContent().getContent();
065        if (requestDocument.getUuid() == null || requestDocument.getUuid().trim().length() == 0) {
066            requestDocument.setUuid(requestDocument.getId());
067        }
068        //        uuid = requestDocument.getUuid();
069        //        ingestDocs.add(sb.toString());
070        //        uuids.add(uuid);
071        if (DocType.INSTANCE.getCode().equalsIgnoreCase(requestDocument.getType()) && content == null
072                && requestDocument.getId() != null) {
073            for (RequestDocument linkedItemDocument : requestDocument.getLinkedRequestDocuments()) {
074                if (DocType.ITEM.getDescription().equalsIgnoreCase(linkedItemDocument.getType())
075                        && linkedItemDocument.getContent().getContent() != null) {
076                    ingestNIndexItemRecForInstance(requestDocument);
077                }
078            }
079        }
080        if (!DocType.SOURCEHOLDINGS.getDescription().equalsIgnoreCase(requestDocument.getType())) {
081            String result = ServiceLocator.getIndexerService().indexDocument(requestDocument);
082            if (!result.startsWith("success")) {
083                throw new OleException(checkInFail + result);
084            }
085        }
086        Session session = null;
087        try {
088            latestVersion = updateRecordInDocStore(requestDocument);
089        } catch (Exception e) {
090            docStoreLogger
091                    .log("Document was updated in indexer but not in docStore, trying to rollback the changes from indexer",
092                            e);
093
094            RequestDocument prevRequestDoc = null;
095            session = RepositoryManager.getRepositoryManager().getSession("CheckinManager", "checkIn");
096            Node nodeByUUID = getNodeByUUID(session, requestDocument.getId());
097            try {
098                DocumentIndexer documentIndexer = new DocumentIndexer();
099                prevRequestDoc = new RequestDocument();
100                prevRequestDoc = requestDocument;
101                String prevContent = nodeByUUID.getNode("jcr:content").getProperty("jcr:data").getValue().getString();
102                prevRequestDoc.getContent().setContent(prevContent);
103                documentIndexer.indexDocument(prevRequestDoc);
104            } catch (Exception ex) {
105                String failMsg = checkInFail + "Unable to Roll back the changes in indexer.  Record UUID "
106                        + requestDocument.getId() + "got updated in indexer, but not in docstore ";
107                docStoreLogger.log(failMsg, ex);
108                throw new OleException(failMsg, ex);
109
110            }
111            docStoreLogger.log(checkInFail, e);
112            throw new OleException(checkInFail, e);
113        } finally {
114            RepositoryManager.getRepositoryManager().logout(session);
115        }
116
117
118        return latestVersion;
119    }
120
121    private void ingestNIndexItemRecForInstance(RequestDocument reqDoc) throws OleException {
122        Session session = null;
123        try {
124            session = RepositoryManager.getRepositoryManager()
125                    .getSession("CheckinManager", "ingestNIndexItemRecForInstance");
126            Node nodeByUUID = getNodeByUUID(session, reqDoc.getId());
127            Node holdingsNode = nodeByUUID.getNode(ProcessParameters.NODE_HOLDINGS);
128            NodeHandler nodeHandler = new NodeHandler();
129
130            for (RequestDocument linkedItemDocument : reqDoc.getLinkedRequestDocuments()) {
131                ItemOlemlRecordProcessor recordProcessor = new ItemOlemlRecordProcessor();
132                Item item = recordProcessor.fromXML(linkedItemDocument.getContent().getContent());
133                linkedItemDocument.getContent().setContentObject(item);
134                String uuid = (nodeHandler.initFileNode(linkedItemDocument, FILE_ITEM, holdingsNode, session))
135                        .getIdentifier();
136                linkedItemDocument.setId(uuid);
137            }
138            session.save();
139        } catch (Exception e) {
140            docStoreLogger.log(e.getMessage());
141            throw new OleException(e.getMessage(), e);
142        } finally {
143            RepositoryManager.getRepositoryManager().logout(session);
144        }
145    }
146
147
148    private String updateRecordInDocStore(RequestDocument reqDoc) throws OleException, RepositoryException {
149        Session session = RepositoryManager.getRepositoryManager()
150                .getSession("CheckinManager", "updateRecordInDocStore");
151        String charset = "UTF-8";
152        byte[] documentBytes = null;
153        String currentVersion = null;
154
155        try {
156            if (reqDoc.getDocumentName() != null && reqDoc.getDocumentName().trim().length() != 0) {
157                documentBytes = FileUtils.readFileToByteArray(new File(reqDoc.getDocumentName()));
158            } else if (reqDoc.getContent().getContent() != null) {
159                setIdentifierValueInContent(reqDoc);
160                documentBytes = reqDoc.getContent().getContent().getBytes(charset);
161            }
162        } catch (Exception e) {
163            getDocStoreLogger().log("Failed to convert input string to byte[] with charset " + charset, e);
164            throw new OleException(e.getMessage());
165        }
166        RequestDocument linkReqInfo = new RequestDocument();
167        if (reqDoc.getLinkedRequestDocuments() != null && reqDoc.getLinkedRequestDocuments().size() > 0) {
168            for (Iterator<RequestDocument> linkIterator = reqDoc.getLinkedRequestDocuments().iterator(); linkIterator
169                    .hasNext(); ) {
170                linkReqInfo = linkIterator.next();
171            }
172        }
173        Node nodeByUUID = session.getNodeByIdentifier(reqDoc.getUuid());
174        try {
175            Binary binary = null;
176            if (documentBytes != null) {
177                binary = session.getValueFactory().createBinary(new ByteArrayInputStream(documentBytes));
178                nodeByUUID.getNode("jcr:content").setProperty("jcr:data", binary);
179            }
180            if (linkReqInfo != null && linkReqInfo.getId() != null && linkReqInfo.getType().equalsIgnoreCase(
181                    DocType.INSTANCE.getCode())) {
182                nodeByUUID.setProperty("instanceIdentifier", linkReqInfo.getId());
183            }
184            Calendar lastModified = Calendar.getInstance();
185            lastModified.setTimeInMillis(lastModified.getTimeInMillis());
186            if (!reqDoc.getType().equalsIgnoreCase(DocType.INSTANCE.getCode())) {
187                nodeByUUID.getNode("jcr:content").setProperty("jcr:lastModified", lastModified);
188            }
189            session.save();
190            if (DocStoreConstants.isVersioningEnabled || DocType.LICENSE.isEqualTo(reqDoc.getType())) {
191                VersionManager versionManager = getVersionManager(session);
192                versionManager.checkpoint(nodeByUUID.getPath());
193                VersionHistory versionHistory = versionManager.getVersionHistory(nodeByUUID.getPath());
194                VersionIterator allVersions = versionHistory.getAllVersions();
195                while (allVersions.hasNext()) {
196                    currentVersion = allVersions.nextVersion().getName();
197                }
198                getDocStoreLogger()
199                        .log("Version updated for UUID:" + reqDoc.getUuid() + "  ====  version:" + currentVersion);
200            }
201        } catch (Exception e) {
202            docStoreLogger.log(e.getMessage());
203            throw new OleException(e.getMessage(), e);
204        } finally {
205            RepositoryManager.getRepositoryManager().logout(session);
206        }
207        return currentVersion;
208    }
209
210    private void setIdentifierValueInContent(RequestDocument reqDoc) {
211        if (reqDoc.getType().equalsIgnoreCase(DocType.ITEM.getDescription())) {
212            ItemOlemlRecordProcessor recordProcessor = new ItemOlemlRecordProcessor();
213            Item item = recordProcessor.fromXML(reqDoc.getContent().getContent());
214            item.setItemIdentifier(reqDoc.getId());
215            reqDoc.getContent().setContent(recordProcessor.toXML(item));
216        }
217        if (reqDoc.getType().equalsIgnoreCase(DocType.HOLDINGS.getDescription())) {
218            HoldingOlemlRecordProcessor recordProcessor = new HoldingOlemlRecordProcessor();
219            OleHoldings holdings = recordProcessor.fromXML(reqDoc.getContent().getContent());
220            holdings.setHoldingsIdentifier(reqDoc.getId());
221            reqDoc.getContent().setContent(recordProcessor.toXML(holdings));
222        }
223        if (reqDoc.getType().equalsIgnoreCase(DocType.SOURCEHOLDINGS.getDescription())) {
224            SourceHoldingOlemlRecordProcessor recordProcessor = new SourceHoldingOlemlRecordProcessor();
225            SourceHoldings sourceHoldings = recordProcessor.fromXML(reqDoc.getContent().getContent());
226            sourceHoldings.setHoldingsIdentifier(reqDoc.getId());
227            reqDoc.getContent().setContent(recordProcessor.toXML(sourceHoldings));
228        }
229    }
230
231    private Node getNodeByUUID(Session newSession, String uuid) throws OleException {
232        return new NodeHandler().getNodeByUUID(newSession, uuid);
233    }
234
235    public DocStoreLogger getDocStoreLogger() {
236        return docStoreLogger;
237    }
238
239    public VersionManager getVersionManager(Session session) throws OleException, RepositoryException {
240        return session.getWorkspace().getVersionManager();
241    }
242}