001package org.kuali.ole.batch.impl;
002
003import org.apache.commons.lang.StringUtils;
004import org.apache.log4j.Logger;
005import org.apache.solr.common.SolrDocument;
006import org.kuali.ole.BibliographicRecordHandler;
007import org.kuali.ole.batch.bo.OLEBatchProcessProfileBo;
008import org.kuali.ole.batch.helper.EInstanceMappingHelper;
009import org.kuali.ole.batch.helper.InstanceMappingHelper;
010import org.kuali.ole.batch.helper.OLEBatchProcessDataHelper;
011import org.kuali.ole.batch.service.ExportDataService;
012import org.kuali.ole.describe.service.DocstoreHelperService;
013import org.kuali.ole.docstore.discovery.solr.work.bib.WorkBibCommonFields;
014import org.kuali.ole.docstore.discovery.solr.work.instance.WorkInstanceCommonFields;
015import org.kuali.ole.docstore.model.enums.DocType;
016import org.kuali.ole.docstore.model.xmlpojo.work.bib.marc.DataField;
017import org.kuali.ole.docstore.model.xmlpojo.work.instance.oleml.InstanceCollection;
018import org.kuali.ole.pojo.bib.BibliographicRecord;
019
020import java.util.ArrayList;
021import java.util.Collections;
022import java.util.Date;
023import java.util.List;
024
025import static org.kuali.ole.OLEConstants.OLEBatchProcess.*;
026
027/**
028 * Created with IntelliJ IDEA.
029 * User: meenrajd
030 * Date: 7/5/13
031 * Time: 2:38 PM
032 */
033public class ExportDataServiceImpl implements ExportDataService {
034
035    private static final Logger LOG = Logger.getLogger(ExportDataServiceImpl.class);
036
037    private static volatile ExportDataService service = new ExportDataServiceImpl();
038    private static volatile List<String> bibIdList = new ArrayList<>();
039
040    private ExportDataServiceImpl() {
041    }
042
043    public static synchronized ExportDataService getInstance() {
044        bibIdList.clear();
045        return service;
046    }
047
048    /**
049     * public method to retrieves the list of bib / instance records for the given profile
050     *
051     * Returns object array - array size is  4
052     * Following positions of the array has the details of the data it contains
053     * 0 - has the count of bib records
054     * 1 - List with xml data of the bib records , if the export type is marc xml the list will have only one item will
055     * all the bib records in a single String object, if the export type is marc the list will have each record as an item
056     * 2 - Errors generated
057     * 3 -  Error count
058     *
059     * @param solrDocumentList
060     * @param profile
061     * @return
062     * @throws Exception
063     */
064    public Object[] getExportDataBySolr(List<SolrDocument> solrDocumentList, OLEBatchProcessProfileBo profile) throws Exception {
065        List<String> bibMarcRecordList = new ArrayList<String>();
066        DocstoreHelperService helperService = new DocstoreHelperService();
067        List<BibliographicRecord> bibRecords = new ArrayList<BibliographicRecord>();
068        StringBuilder errBuilder = new StringBuilder();
069        int errCnt = 0;
070        for (SolrDocument solrDocument : solrDocumentList) {
071            try {
072                String bibId = getBibId(solrDocument);
073                if (bibIdList.contains(bibId)) continue;
074                else bibIdList.add(bibId);
075                List<String> instanceIdentifierList = new ArrayList<String>();
076                if (solrDocument.getFieldValue(WorkBibCommonFields.DOC_TYPE).equals(DocType.INSTANCE.getDescription())) {
077                    String instanceIdentifier = (String) solrDocument.getFieldValue(WorkBibCommonFields.ID);
078                    instanceIdentifierList.add(instanceIdentifier);
079                } else if (solrDocument.getFieldValue(WorkInstanceCommonFields.INSTANCE_IDENTIFIER) != null) {
080                    if (solrDocument.getFieldValue(WorkInstanceCommonFields.INSTANCE_IDENTIFIER) instanceof List) {
081                        instanceIdentifierList = (List<String>) solrDocument.getFieldValue(WorkInstanceCommonFields.INSTANCE_IDENTIFIER);
082                    } else {
083                        String instanceIdentifier = (String) solrDocument.getFieldValue(WorkInstanceCommonFields.INSTANCE_IDENTIFIER);
084                        instanceIdentifierList.add(instanceIdentifier);
085                    }
086                }
087                try {
088                    BibliographicRecord bibliographicRecord = helperService.getBibliographicRecord(bibId);
089                    //Intance mapping
090                    if (!instanceIdentifierList.isEmpty() && !profile.getOleBatchProcessProfileDataMappingOptionsBoList().isEmpty()
091                            && StringUtils.isNotEmpty(profile.getDataToExport()) && profile.getDataToExport().equalsIgnoreCase(OLEBatchProcess.EXPORT_BIB_AND_INSTANCE)) {
092                        try {
093                            getInstanceDetails(bibliographicRecord, instanceIdentifierList, profile, errBuilder);
094                            LOG.info("Instance data mapping completed");
095                        } catch (Exception ex) {
096                            LOG.error("Instance data mapping Error for Bib record id::" + bibliographicRecord.getRecordId(),ex);
097                            buildError(errBuilder,ERR_BIB,bibliographicRecord.getRecordId(),"Instance Id(s)",instanceIdentifierList.toString(),
098                                    ERR_CAUSE,ex.getMessage(),TIME_STAMP,new Date().toString());
099                            errCnt++;
100                            continue;
101                        }
102                    }
103                    //Marc record rename
104                    if (!profile.getOleBatchProcessProfileRenameFieldsList().isEmpty()) {
105                        try {
106                            OLEBatchProcessDataHelper.getInstance().renameMarcFieldsSubFields(profile, bibliographicRecord);
107                            LOG.info("Rename of bib marc records completed");
108                        } catch (Exception ex) {
109                            LOG.error("Marc Record Rename error for Bib record id::" + bibliographicRecord.getRecordId(),ex);
110                            buildError(errBuilder,ERR_BIB,bibliographicRecord.getRecordId(),ERR_CAUSE,ex.getMessage()," ::At:: ","renameMarcFieldsSubFields",TIME_STAMP,new Date().toString());
111                            errCnt++;
112                            continue;
113                        }
114                    }
115                    //Marc record delete
116                    if (!profile.getOleBatchProcessProfileDeleteFieldsList().isEmpty()) {
117                        try {
118                            OLEBatchProcessDataHelper.getInstance().deleteFieldsSubfields(profile, bibliographicRecord);
119                            LOG.info("Deletion of bib marc records completed");
120                        } catch (Exception ex) {
121                            LOG.error("Marc record delete Error for Bib record id::" + bibliographicRecord.getRecordId(),ex);
122                            buildError(errBuilder,ERR_BIB,bibliographicRecord.getRecordId(),ERR_CAUSE,ex.getMessage()," ::At:: ","deleteFieldsSubfields",TIME_STAMP,new Date().toString());
123                            errCnt++;
124                            continue;
125                        }
126                    }
127                    //Setting record id as 001 field
128                    try {
129                        OLEBatchProcessDataHelper.getInstance().setRecordNumber(bibliographicRecord, solrDocument.getFieldValue(WorkBibCommonFields.LOCALID_SEARCH).toString());
130                    } catch (Exception ex) {
131                        LOG.error("Error while setting record number for record id::" + bibliographicRecord.getRecordId(),ex);
132                        buildError(errBuilder,ERR_BIB,bibliographicRecord.getRecordId(),ERR_CAUSE,ex.getMessage()," ::At:: ","setRecordNumber",TIME_STAMP,new Date().toString());
133                        errCnt++;
134                        continue;
135                    }
136                    bibRecords.add(bibliographicRecord);
137                } catch (Exception ex) {
138                    LOG.error("Error while getting bib information for record id::" + bibId,ex);
139                    buildError(errBuilder,ERR_BIB,bibId,ERR_CAUSE,ex.getMessage()," ::At:: ","getBibliographicRecord",TIME_STAMP,new Date().toString());
140                    errCnt++;
141                }
142            } catch (Exception ex) {
143                LOG.error("Error while Exporting bibs :: No of bibs processed while error occured :: " + bibIdList.size(),ex);
144
145                if (!bibIdList.isEmpty()) {
146                    LOG.error("Bib record where error occured: " + bibIdList.get(bibIdList.size() - 1), ex);
147                   buildError(errBuilder,ERR_BIB,bibIdList.get(bibIdList.size() - 1),ERR_CAUSE,ex.getMessage()," ::At:: ","getBibliographicRecord-P",TIME_STAMP,new Date().toString());
148                   errCnt++;
149                }
150            }
151        }//End loop of bib ids
152        BibliographicRecordHandler bibliographicRecordHandler = new BibliographicRecordHandler(errBuilder);
153        try{
154            if(profile.getFileType().equalsIgnoreCase(OLEBatchProcess.MARCXML)){
155                getResult(bibliographicRecordHandler,bibRecords,bibMarcRecordList);
156            }else if(profile.getFileType().equalsIgnoreCase(OLEBatchProcess.MARC)){
157                for(BibliographicRecord record : bibRecords){
158                    getResult(bibliographicRecordHandler,record,bibMarcRecordList);
159                }
160            }
161        }catch (Exception ex) {
162            LOG.error("Error while Exporting bibs :: No of bibs processed while error occured :: " + bibIdList.size(),ex);
163            buildError(errBuilder,ERR_CAUSE,"Error while getting bib data::"+ex.getMessage(),TIME_STAMP,new Date().toString());
164        }
165        return new Object[]{String.valueOf(bibRecords.size()), bibMarcRecordList, errBuilder.toString(), String.valueOf((errCnt + bibliographicRecordHandler.getErrCnt()))};
166
167    }
168
169
170    /**
171     * Method retrives the list of instances record for the bib record with the given instanceIdentifier list
172     *
173     * @param bibliographicRecord
174     * @param instanceIdentifierList
175     * @param profile
176     */
177    private void getInstanceDetails(BibliographicRecord bibliographicRecord, List<String> instanceIdentifierList, OLEBatchProcessProfileBo profile, StringBuilder errBuilder) throws Exception {
178        DocstoreHelperService helperService = new DocstoreHelperService();
179        List<DataField> dataFields = bibliographicRecord.getDatafields();
180        for (String instanceIdentifier : instanceIdentifierList) {
181            Object object = helperService.getInstanceCollectionData(instanceIdentifier);
182            List<DataField> instanceItemDataField = Collections.emptyList();
183            if(object instanceof InstanceCollection){
184                InstanceCollection instanceCollection = (InstanceCollection)object;
185                instanceItemDataField = new InstanceMappingHelper().generateDataField(instanceCollection, profile, errBuilder);
186            }else if(object instanceof org.kuali.ole.docstore.model.xmlpojo.work.einstance.oleml.InstanceCollection){
187                org.kuali.ole.docstore.model.xmlpojo.work.einstance.oleml.InstanceCollection instanceCollection = (org.kuali.ole.docstore.model.xmlpojo.work.einstance.oleml.InstanceCollection)object;
188                if(instanceCollection!=null){
189                    LOG.info("eInstance Collection :: "+instanceCollection.getEInstance().toString()+"processed");
190                    instanceItemDataField = new EInstanceMappingHelper().generateDataField(instanceCollection,profile,errBuilder);
191                }
192
193            }
194            dataFields.addAll(instanceItemDataField);
195        }
196    }
197
198    /**
199     * Pubic method that retrieves the list of bib / instance records for the given profile an additional task this method
200     * does is to prepare solr query to get the solr doc list
201     *
202     * @param bibIds
203     * @param profile
204     * @return
205     * @throws Exception
206     */
207    public Object[] getExportDataByBibIds(List<String> bibIds, OLEBatchProcessProfileBo profile) throws Exception {
208        //TODO need to prepare the solr query to retrieve the solr document list for the given bib ids
209        List<SolrDocument> solrDocumentList = Collections.EMPTY_LIST;
210        return getExportDataBySolr(solrDocumentList, profile);
211    }
212
213    /**
214     * returns the bib id for the solr document
215     *
216     * @param solrDocument
217     * @return
218     */
219    private String getBibId(SolrDocument solrDocument) {
220        String docType = solrDocument.getFieldValue(WorkBibCommonFields.DOC_TYPE).toString();
221        if (docType.equals(DocType.BIB.getDescription())) {
222            return solrDocument.getFieldValue(WorkBibCommonFields.ID).toString();
223        } else if (docType.equals(DocType.INSTANCE.getDescription())
224                || docType.equals(DocType.HOLDINGS.getDescription())
225                || docType.equals(DocType.ITEM.getDescription())) {
226            return solrDocument.getFieldValue(WorkInstanceCommonFields.BIB_IDENTIFIER).toString();
227        } else {
228            return "";
229        }
230    }
231
232    private void getResult(BibliographicRecordHandler bibliographicRecordHandler,List<BibliographicRecord> bibRecords,List<String> bibMarcRecordList){
233        String bibMarcRecord = bibliographicRecordHandler.generateXML(bibRecords);
234        bibMarcRecordList.add(bibMarcRecord);
235    }
236
237    private void getResult(BibliographicRecordHandler bibliographicRecordHandler,BibliographicRecord bibRecords,List<String> bibMarcRecordList){
238        String bibMarcRecord = bibliographicRecordHandler.generateXML(bibRecords);
239        bibMarcRecordList.add(bibMarcRecord);
240    }
241
242    private void buildError(StringBuilder errBuilder,String...errorString){
243        for(String str : errorString){
244            errBuilder.append(str).append(COMMA);
245        }
246        errBuilder.append(lineSeparator);
247    }
248}