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