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