001    /**
002     * Copyright 2005-2014 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.rice.kew.impl.document.attribute;
017    
018    import org.apache.commons.lang.StringUtils;
019    import org.apache.log4j.Logger;
020    import org.apache.log4j.MDC;
021    import org.joda.time.DateTime;
022    import org.kuali.rice.core.api.exception.RiceIllegalArgumentException;
023    import org.kuali.rice.kew.api.KewApiServiceLocator;
024    import org.kuali.rice.kew.api.WorkflowRuntimeException;
025    import org.kuali.rice.kew.api.document.Document;
026    import org.kuali.rice.kew.api.document.DocumentContent;
027    import org.kuali.rice.kew.api.document.DocumentWithContent;
028    import org.kuali.rice.kew.api.document.WorkflowDocumentService;
029    import org.kuali.rice.kew.api.document.attribute.DocumentAttribute;
030    import org.kuali.rice.kew.api.document.attribute.DocumentAttributeDateTime;
031    import org.kuali.rice.kew.api.document.attribute.DocumentAttributeDecimal;
032    import org.kuali.rice.kew.api.document.attribute.DocumentAttributeIndexingQueue;
033    import org.kuali.rice.kew.api.document.attribute.DocumentAttributeInteger;
034    import org.kuali.rice.kew.api.document.attribute.DocumentAttributeString;
035    import org.kuali.rice.kew.docsearch.SearchableAttributeDateTimeValue;
036    import org.kuali.rice.kew.docsearch.SearchableAttributeFloatValue;
037    import org.kuali.rice.kew.docsearch.SearchableAttributeLongValue;
038    import org.kuali.rice.kew.docsearch.SearchableAttributeStringValue;
039    import org.kuali.rice.kew.docsearch.SearchableAttributeValue;
040    import org.kuali.rice.kew.doctype.bo.DocumentType;
041    import org.kuali.rice.kew.framework.document.attribute.SearchableAttribute;
042    import org.kuali.rice.kew.service.KEWServiceLocator;
043    
044    import java.math.BigInteger;
045    import java.sql.Timestamp;
046    import java.util.ArrayList;
047    import java.util.List;
048    
049    /**
050     * Reference implementation of the DocumentAttributeIndexingQueue.
051     *
052     * @author Kuali Rice Team (rice.collab@kuali.org)
053     */
054    public 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    }