001/**
002 * Copyright 2005-2016 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.rice.kew.impl.document.attribute;
017
018import org.apache.commons.lang.StringUtils;
019import org.apache.log4j.Logger;
020import org.apache.log4j.MDC;
021import org.joda.time.DateTime;
022import org.kuali.rice.core.api.exception.RiceIllegalArgumentException;
023import org.kuali.rice.kew.api.KewApiServiceLocator;
024import org.kuali.rice.kew.api.WorkflowRuntimeException;
025import org.kuali.rice.kew.api.document.Document;
026import org.kuali.rice.kew.api.document.DocumentContent;
027import org.kuali.rice.kew.api.document.DocumentWithContent;
028import org.kuali.rice.kew.api.document.WorkflowDocumentService;
029import org.kuali.rice.kew.api.document.attribute.DocumentAttribute;
030import org.kuali.rice.kew.api.document.attribute.DocumentAttributeDateTime;
031import org.kuali.rice.kew.api.document.attribute.DocumentAttributeDecimal;
032import org.kuali.rice.kew.api.document.attribute.DocumentAttributeIndexingQueue;
033import org.kuali.rice.kew.api.document.attribute.DocumentAttributeInteger;
034import org.kuali.rice.kew.api.document.attribute.DocumentAttributeString;
035import org.kuali.rice.kew.docsearch.SearchableAttributeDateTimeValue;
036import org.kuali.rice.kew.docsearch.SearchableAttributeFloatValue;
037import org.kuali.rice.kew.docsearch.SearchableAttributeLongValue;
038import org.kuali.rice.kew.docsearch.SearchableAttributeStringValue;
039import org.kuali.rice.kew.docsearch.SearchableAttributeValue;
040import org.kuali.rice.kew.doctype.bo.DocumentType;
041import org.kuali.rice.kew.framework.document.attribute.SearchableAttribute;
042import org.kuali.rice.kew.service.KEWServiceLocator;
043
044import java.math.BigInteger;
045import java.sql.Timestamp;
046import java.util.ArrayList;
047import java.util.List;
048
049/**
050 * Reference implementation of the DocumentAttributeIndexingQueue.
051 *
052 * @author Kuali Rice Team (rice.collab@kuali.org)
053 */
054public class DocumentAttributeIndexingQueueImpl implements DocumentAttributeIndexingQueue {
055
056        private static Logger LOG = Logger.getLogger(DocumentAttributeIndexingQueueImpl.class);
057
058    @Override
059    public void indexDocument(String documentId) {
060        if (StringUtils.isBlank(documentId)) {
061            throw new RiceIllegalArgumentException("documentId was null or blank");
062        }
063        MDC.put("docId", documentId);
064        try {
065            long t1 = System.currentTimeMillis();
066            LOG.info("Indexing document attributes for document " + documentId);
067            Document document = getWorkflowDocumentService().getDocument(documentId);
068            if (document == null) {
069                throw new RiceIllegalArgumentException("Failed to locate document with the given id: " + documentId);
070            }
071            DocumentContent documentContent =
072                    KewApiServiceLocator.getWorkflowDocumentService().getDocumentContent(documentId);
073            List<SearchableAttributeValue> attributes = buildSearchableAttributeValues(document, documentContent);
074            KEWServiceLocator.getRouteHeaderService().updateRouteHeaderSearchValues(documentId, attributes);
075            long t2 = System.currentTimeMillis();
076            LOG.info("...finished indexing document " + documentId + " for document search, total time = " + (t2 - t1) +
077                    " ms.");
078        } finally {
079            MDC.remove("docId");
080        }
081    }
082
083    /**
084     * Determines the {@link DocumentAttribute}s for the given document and returns a List of SearchableAttributeValue
085     * which will be saved.
086     */
087        private List<SearchableAttributeValue> buildSearchableAttributeValues(Document document, DocumentContent documentContent) {
088                List<SearchableAttributeValue> searchableAttributeValues = new ArrayList<SearchableAttributeValue>();
089        DocumentType documentTypeBo = KEWServiceLocator.getDocumentTypeService().findByName(document.getDocumentTypeName());
090                for (DocumentType.ExtensionHolder<SearchableAttribute> searchableAttributeHolder : documentTypeBo.loadSearchableAttributes()) {
091            DocumentWithContent documentWithContent = DocumentWithContent.create(document, documentContent);
092            SearchableAttribute searchableAttribute = searchableAttributeHolder.getExtension();
093            List<DocumentAttribute> documentAttributes = searchableAttribute.extractDocumentAttributes(
094                    searchableAttributeHolder.getExtensionDefinition(), documentWithContent);
095                        if (documentAttributes != null) {
096                for (DocumentAttribute documentAttribute : documentAttributes) {
097                    if (documentAttribute == null) {
098                        LOG.warn("Encountered a 'null' DocumentAttribute from searchable attribute: " + searchableAttribute);
099                        continue;
100                    }
101                    SearchableAttributeValue searchableAttributeValue = null;
102                    if (documentAttribute instanceof DocumentAttributeString) {
103                        searchableAttributeValue = new SearchableAttributeStringValue();
104                        ((SearchableAttributeStringValue)searchableAttributeValue).setSearchableAttributeValue(((DocumentAttributeString)documentAttribute).getValue());
105                    } else if (documentAttribute instanceof DocumentAttributeDateTime) {
106                        searchableAttributeValue = new SearchableAttributeDateTimeValue();
107                        DateTime dateTimeValue = ((DocumentAttributeDateTime)documentAttribute).getValue();
108                        Timestamp timestamp = (dateTimeValue == null ? null : new Timestamp(dateTimeValue.getMillis()));
109                        ((SearchableAttributeDateTimeValue)searchableAttributeValue).setSearchableAttributeValue(timestamp);
110                    } else if (documentAttribute instanceof DocumentAttributeInteger) {
111                        searchableAttributeValue = new SearchableAttributeLongValue();
112                        BigInteger bigIntegerValue = ((DocumentAttributeInteger)documentAttribute).getValue();
113                        Long longValue = (bigIntegerValue == null ? null : bigIntegerValue.longValue());
114                        ((SearchableAttributeLongValue)searchableAttributeValue).setSearchableAttributeValue(longValue);
115                    } else if (documentAttribute instanceof DocumentAttributeDecimal) {
116                        searchableAttributeValue = new SearchableAttributeFloatValue();
117                        ((SearchableAttributeFloatValue)searchableAttributeValue).setSearchableAttributeValue(((DocumentAttributeDecimal)documentAttribute).getValue());
118                    } else {
119                        throw new WorkflowRuntimeException("Encountered an invalid instance of DocumentAttribute, was: " + documentAttribute.getClass());
120                    }
121                    searchableAttributeValue.setSearchableAttributeKey(documentAttribute.getName());
122                    searchableAttributeValue.setDocumentId(document.getDocumentId());
123                    searchableAttributeValue.setRouteHeader(null); // let the documentId we set represent this reference
124                    searchableAttributeValues.add(searchableAttributeValue);
125                }
126                        }
127                }
128                return searchableAttributeValues;
129        }
130
131    protected WorkflowDocumentService getWorkflowDocumentService() {
132        return KewApiServiceLocator.getWorkflowDocumentService();
133    }
134}