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