001/*
002 * Copyright (c) 2006-2014 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 *
009 * Contributors:
010 *     Florent Guillaume
011 *     Stephane Lacoin
012 */
013package org.nuxeo.ecm.core.storage;
014
015import java.io.Serializable;
016import java.util.Collection;
017import java.util.Collections;
018import java.util.List;
019
020import org.apache.commons.logging.Log;
021import org.apache.commons.logging.LogFactory;
022import org.nuxeo.ecm.core.api.DocumentModel;
023import org.nuxeo.ecm.core.api.DocumentRef;
024import org.nuxeo.ecm.core.api.IdRef;
025import org.nuxeo.ecm.core.work.AbstractWork;
026import org.nuxeo.ecm.core.work.api.WorkManager;
027
028/**
029 * Work task that inserts the fulltext (extracted manually by the session at save time, or through
030 * FulltextExtractorWork) into the fulltext table.
031 * <p>
032 * This is done single-threaded through the use of a {@link WorkManager} queue with only one thread.
033 */
034public class FulltextUpdaterWork extends AbstractWork {
035
036    private static final long serialVersionUID = 1L;
037
038    private static final Log log = LogFactory.getLog(FulltextUpdaterWork.class);
039
040    public static final String SYSPROP_FULLTEXT_SIMPLE = "fulltextSimple";
041
042    public static final String SYSPROP_FULLTEXT_BINARY = "fulltextBinary";
043
044    public static final String SYSPROP_FULLTEXT_JOBID = "fulltextJobId";
045
046    public static final String FULLTEXT_DEFAULT_INDEX = "default";
047
048    protected static final String CATEGORY = "fulltextUpdater";
049
050    protected static final String TITLE = "Fulltext Updater";
051
052    /** Is this a simple text index or a binary text one. */
053    protected final boolean isSimpleText;
054
055    /** If true, then all the documents with the id as their jobId are updated. */
056    protected final boolean isJob;
057
058    /** The indexes and text to be updated. */
059    protected final List<IndexAndText> indexesAndText;
060
061    public static class IndexAndText implements Serializable {
062        private static final long serialVersionUID = 1L;
063
064        public String indexName;
065
066        public String text;
067
068        public IndexAndText(String indexName, String text) {
069            this.indexName = indexName;
070            this.text = text;
071        }
072    }
073
074    public FulltextUpdaterWork(String repositoryName, String docId, boolean isSimpleText, boolean isJob,
075            List<IndexAndText> indexesAndText) {
076        super(); // random id, for unique job
077        setDocument(repositoryName, docId);
078        this.isSimpleText = isSimpleText;
079        this.isJob = isJob;
080        this.indexesAndText = indexesAndText;
081    }
082
083    @Override
084    public String getCategory() {
085        return CATEGORY;
086    }
087
088    @Override
089    public String getTitle() {
090        return TITLE;
091    }
092
093    @Override
094    public int getRetryCount() {
095        return 1;
096    }
097
098    @Override
099    public void work() {
100        initSession();
101        // if the runtime has shut down (normally because tests are finished)
102        // this can happen, see NXP-4009
103        if (session.getPrincipal() == null) {
104            return;
105        }
106
107        setProgress(Progress.PROGRESS_0_PC);
108        setStatus("Updating");
109        update();
110        setStatus("Saving");
111        session.save();
112        setStatus("Done");
113    }
114
115    protected void update() {
116        Collection<DocumentModel> docs;
117        if (isJob) {
118            String query = String.format("SELECT * FROM Document WHERE ecm:fulltextJobId = '%s' AND ecm:isProxy = 0",
119                    docId);
120            docs = session.query(query);
121        } else {
122            DocumentRef ref = new IdRef(docId);
123            if (!session.exists(ref)) {
124                // doc is gone
125                return;
126            }
127            DocumentModel doc = session.getDocument(ref);
128            if (doc.isProxy()) {
129                // proxies don't have any fulltext attached, it's
130                // the target document that carries it
131                return;
132            }
133            docs = Collections.singleton(doc);
134        }
135        for (DocumentModel doc : docs) {
136            for (IndexAndText indexAndText : indexesAndText) {
137                session.setDocumentSystemProp(doc.getRef(), getFulltextPropertyName(indexAndText.indexName),
138                        indexAndText.text);
139            }
140        }
141        if (isJob) {
142            // reset job id
143            for (DocumentModel doc : docs) {
144                session.setDocumentSystemProp(doc.getRef(), SYSPROP_FULLTEXT_JOBID, null);
145            }
146        }
147    }
148
149    protected String getFulltextPropertyName(String indexName) {
150        String name = isSimpleText ? SYSPROP_FULLTEXT_SIMPLE : SYSPROP_FULLTEXT_BINARY;
151        if (!FULLTEXT_DEFAULT_INDEX.equals(indexName)) {
152            name += '_' + indexName;
153        }
154        return name;
155    }
156
157}