001/* 002 * (C) Copyright 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 * Thierry Delprat 018 * Benoit Delbosc 019 */ 020 021package org.nuxeo.elasticsearch.commands; 022 023import org.apache.commons.logging.Log; 024import org.apache.commons.logging.LogFactory; 025import org.nuxeo.ecm.core.api.DocumentModel; 026import org.nuxeo.ecm.core.api.LifeCycleConstants; 027import org.nuxeo.ecm.core.event.impl.DocumentEventContext; 028import org.nuxeo.elasticsearch.ElasticSearchConstants; 029import org.nuxeo.elasticsearch.commands.IndexingCommand.Type; 030import java.util.Map; 031 032import static org.nuxeo.ecm.core.api.event.DocumentEventTypes.BEFORE_DOC_UPDATE; 033import static org.nuxeo.ecm.core.api.event.DocumentEventTypes.BINARYTEXT_UPDATED; 034import static org.nuxeo.ecm.core.api.event.DocumentEventTypes.DOCUMENT_CHECKEDIN; 035import static org.nuxeo.ecm.core.api.event.DocumentEventTypes.DOCUMENT_CHECKEDOUT; 036import static org.nuxeo.ecm.core.api.event.DocumentEventTypes.DOCUMENT_CHILDREN_ORDER_CHANGED; 037import static org.nuxeo.ecm.core.api.event.DocumentEventTypes.DOCUMENT_CREATED; 038import static org.nuxeo.ecm.core.api.event.DocumentEventTypes.DOCUMENT_CREATED_BY_COPY; 039import static org.nuxeo.ecm.core.api.event.DocumentEventTypes.DOCUMENT_MOVED; 040import static org.nuxeo.ecm.core.api.event.DocumentEventTypes.DOCUMENT_PROXY_UPDATED; 041import static org.nuxeo.ecm.core.api.event.DocumentEventTypes.DOCUMENT_REMOVED; 042import static org.nuxeo.ecm.core.api.event.DocumentEventTypes.DOCUMENT_SECURITY_UPDATED; 043import static org.nuxeo.ecm.core.api.event.DocumentEventTypes.DOCUMENT_TAG_UPDATED; 044 045/** 046 * Contains logic to stack ElasticSearch commands depending on Document events This class is mainly here to make testing 047 * easier 048 */ 049public abstract class IndexingCommandsStacker { 050 051 protected static final Log log = LogFactory.getLog(IndexingCommandsStacker.class); 052 053 protected abstract Map<String, IndexingCommands> getAllCommands(); 054 055 protected abstract boolean isSyncIndexingByDefault(); 056 057 protected IndexingCommands getCommands(DocumentModel doc) { 058 return getAllCommands().get(getDocKey(doc)); 059 } 060 061 public void stackCommand(DocumentEventContext docCtx, String eventId) { 062 DocumentModel doc = docCtx.getSourceDocument(); 063 if (doc == null) { 064 return; 065 } 066 Boolean block = (Boolean) docCtx.getProperty(ElasticSearchConstants.DISABLE_AUTO_INDEXING); 067 if (block != null && block) { 068 if (log.isDebugEnabled()) { 069 log.debug("Indexing is disable, skip indexing command for doc " + doc); 070 } 071 return; 072 } 073 boolean sync = isSynchronous(docCtx, doc); 074 stackCommand(doc, eventId, sync); 075 } 076 077 protected boolean isSynchronous(DocumentEventContext docCtx, DocumentModel doc) { 078 // 1. look at event context 079 Boolean sync = (Boolean) docCtx.getProperty(ElasticSearchConstants.ES_SYNC_INDEXING_FLAG); 080 if (sync != null) { 081 return sync; 082 } 083 // 2. look at document context 084 sync = (Boolean) doc.getContextData().get(ElasticSearchConstants.ES_SYNC_INDEXING_FLAG); 085 if (sync != null) { 086 return sync; 087 } 088 // 3. get the default 089 sync = isSyncIndexingByDefault(); 090 return sync; 091 } 092 093 protected void stackCommand(DocumentModel doc, String eventId, boolean sync) { 094 IndexingCommands cmds = getOrCreateCommands(doc); 095 Type type; 096 boolean recurse = false; 097 switch (eventId) { 098 case DOCUMENT_CREATED: 099 case LifeCycleConstants.TRANSITION_EVENT: 100 type = Type.INSERT; 101 break; 102 case DOCUMENT_CREATED_BY_COPY: 103 type = Type.INSERT; 104 recurse = isFolderish(doc); 105 break; 106 case BEFORE_DOC_UPDATE: 107 case DOCUMENT_CHECKEDOUT: 108 case DOCUMENT_CHECKEDIN: 109 case BINARYTEXT_UPDATED: 110 case DOCUMENT_TAG_UPDATED: 111 case DOCUMENT_PROXY_UPDATED: 112 type = Type.UPDATE; 113 break; 114 case DOCUMENT_MOVED: 115 type = Type.UPDATE; 116 recurse = isFolderish(doc); 117 break; 118 case DOCUMENT_REMOVED: 119 type = Type.DELETE; 120 recurse = isFolderish(doc); 121 break; 122 case DOCUMENT_SECURITY_UPDATED: 123 type = Type.UPDATE_SECURITY; 124 recurse = isFolderish(doc); 125 break; 126 case DOCUMENT_CHILDREN_ORDER_CHANGED: 127 type = Type.UPDATE_DIRECT_CHILDREN; 128 recurse = true; 129 break; 130 default: 131 return; 132 } 133 if (sync && recurse) { 134 // split into 2 commands one sync and an async recurse 135 cmds.add(type, true, false); 136 cmds.add(type, false, true); 137 } else { 138 cmds.add(type, sync, recurse); 139 } 140 } 141 142 private boolean isFolderish(DocumentModel doc) { 143 return doc.isFolder() && ! doc.isVersion(); 144 } 145 146 protected IndexingCommands getOrCreateCommands(DocumentModel doc) { 147 IndexingCommands cmds = getCommands(doc); 148 if (cmds == null) { 149 cmds = new IndexingCommands(doc); 150 getAllCommands().put(getDocKey(doc), cmds); 151 } 152 return cmds; 153 } 154 155 protected String getDocKey(DocumentModel doc) { 156 // Don't merge commands with different session, so we work only on attached doc 157 return doc.getId() + "#" + doc.getSessionId(); 158 } 159 160}