001/* 002 * (C) Copyright 2014 Nuxeo SA (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl-2.1.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Thierry Delprat 016 * Benoit Delbosc 017 */ 018 019package org.nuxeo.elasticsearch.commands; 020 021import static org.nuxeo.ecm.core.api.event.DocumentEventTypes.BEFORE_DOC_UPDATE; 022import static org.nuxeo.ecm.core.api.event.DocumentEventTypes.BINARYTEXT_UPDATED; 023import static org.nuxeo.ecm.core.api.event.DocumentEventTypes.DOCUMENT_CHECKEDIN; 024import static org.nuxeo.ecm.core.api.event.DocumentEventTypes.DOCUMENT_CHECKEDOUT; 025import static org.nuxeo.ecm.core.api.event.DocumentEventTypes.DOCUMENT_CREATED; 026import static org.nuxeo.ecm.core.api.event.DocumentEventTypes.DOCUMENT_CREATED_BY_COPY; 027import static org.nuxeo.ecm.core.api.event.DocumentEventTypes.DOCUMENT_MOVED; 028import static org.nuxeo.ecm.core.api.event.DocumentEventTypes.DOCUMENT_PROXY_UPDATED; 029import static org.nuxeo.ecm.core.api.event.DocumentEventTypes.DOCUMENT_REMOVED; 030import static org.nuxeo.ecm.core.api.event.DocumentEventTypes.DOCUMENT_SECURITY_UPDATED; 031import static org.nuxeo.ecm.core.api.event.DocumentEventTypes.DOCUMENT_TAG_UPDATED; 032 033import java.util.Map; 034 035import org.apache.commons.logging.Log; 036import org.apache.commons.logging.LogFactory; 037import org.nuxeo.ecm.core.api.DocumentModel; 038import org.nuxeo.ecm.core.api.LifeCycleConstants; 039import org.nuxeo.ecm.core.event.impl.DocumentEventContext; 040import org.nuxeo.elasticsearch.ElasticSearchConstants; 041import org.nuxeo.elasticsearch.commands.IndexingCommand.Type; 042import org.nuxeo.runtime.api.Framework; 043 044/** 045 * Contains logic to stack ElasticSearch commands depending on Document events This class is mainly here to make testing 046 * easier 047 */ 048public abstract class IndexingCommandsStacker { 049 050 protected static final Log log = LogFactory.getLog(IndexingCommandsStacker.class); 051 052 protected abstract Map<String, IndexingCommands> getAllCommands(); 053 054 protected abstract boolean isSyncIndexingByDefault(); 055 056 protected IndexingCommands getCommands(DocumentModel doc) { 057 return getAllCommands().get(getDocKey(doc)); 058 } 059 060 public void stackCommand(DocumentEventContext docCtx, String eventId) { 061 if (Framework.isTestModeSet() && Framework.getRuntime().isShuttingDown()) { 062 // avoid processing events generated by the shutdown process in test framework 063 return; 064 } 065 DocumentModel doc = docCtx.getSourceDocument(); 066 if (doc == null) { 067 return; 068 } 069 Boolean block = (Boolean) docCtx.getProperty(ElasticSearchConstants.DISABLE_AUTO_INDEXING); 070 if (block != null && block) { 071 if (log.isDebugEnabled()) { 072 log.debug("Indexing is disable, skip indexing command for doc " + doc); 073 } 074 return; 075 } 076 boolean sync = isSynchronous(docCtx, doc); 077 stackCommand(doc, eventId, sync); 078 } 079 080 protected boolean isSynchronous(DocumentEventContext docCtx, DocumentModel doc) { 081 // 1. look at event context 082 Boolean sync = (Boolean) docCtx.getProperty(ElasticSearchConstants.ES_SYNC_INDEXING_FLAG); 083 if (sync != null) { 084 return sync; 085 } 086 // 2. look at document context 087 sync = (Boolean) doc.getContextData().get(ElasticSearchConstants.ES_SYNC_INDEXING_FLAG); 088 if (sync != null) { 089 return sync; 090 } 091 // 3. get the default 092 sync = isSyncIndexingByDefault(); 093 return sync; 094 } 095 096 protected void stackCommand(DocumentModel doc, String eventId, boolean sync) { 097 IndexingCommands cmds = getOrCreateCommands(doc); 098 Type type; 099 boolean recurse = false; 100 switch (eventId) { 101 case DOCUMENT_CREATED: 102 case LifeCycleConstants.TRANSITION_EVENT: 103 type = Type.INSERT; 104 break; 105 case DOCUMENT_CREATED_BY_COPY: 106 type = Type.INSERT; 107 recurse = doc.isFolder(); 108 break; 109 case BEFORE_DOC_UPDATE: 110 case DOCUMENT_CHECKEDOUT: 111 case DOCUMENT_CHECKEDIN: 112 case BINARYTEXT_UPDATED: 113 case DOCUMENT_TAG_UPDATED: 114 case DOCUMENT_PROXY_UPDATED: 115 type = Type.UPDATE; 116 break; 117 case DOCUMENT_MOVED: 118 type = Type.UPDATE; 119 recurse = doc.isFolder(); 120 break; 121 case DOCUMENT_REMOVED: 122 type = Type.DELETE; 123 recurse = doc.isFolder(); 124 break; 125 case DOCUMENT_SECURITY_UPDATED: 126 type = Type.UPDATE_SECURITY; 127 recurse = doc.isFolder(); 128 break; 129 default: 130 return; 131 } 132 if (sync && recurse) { 133 // split into 2 commands one sync and an async recurse 134 cmds.add(type, true, false); 135 cmds.add(type, false, true); 136 } else { 137 cmds.add(type, sync, recurse); 138 } 139 } 140 141 protected IndexingCommands getOrCreateCommands(DocumentModel doc) { 142 IndexingCommands cmds = getCommands(doc); 143 if (cmds == null) { 144 cmds = new IndexingCommands(doc); 145 getAllCommands().put(getDocKey(doc), cmds); 146 } 147 return cmds; 148 } 149 150 protected String getDocKey(DocumentModel doc) { 151 // Don't merge commands with different session, so we work only on attached doc 152 return doc.getId() + "#" + doc.getSessionId(); 153 } 154 155}