001/* 002 * Copyright 2014 Anyware Services 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 */ 016package org.ametys.web.indexing.observation; 017 018import java.util.Map; 019 020import javax.jcr.Node; 021import javax.jcr.PropertyIterator; 022 023import org.apache.avalon.framework.context.Context; 024import org.apache.avalon.framework.context.ContextException; 025import org.apache.avalon.framework.context.Contextualizable; 026import org.apache.avalon.framework.service.ServiceException; 027import org.apache.avalon.framework.service.ServiceManager; 028import org.apache.avalon.framework.service.Serviceable; 029import org.apache.cocoon.components.ContextHelper; 030import org.apache.cocoon.environment.Request; 031 032import org.ametys.cms.content.indexing.solr.SolrIndexer; 033import org.ametys.cms.content.indexing.solr.observation.ObserverHelper; 034import org.ametys.cms.indexing.IndexingObserver; 035import org.ametys.cms.repository.Content; 036import org.ametys.core.observation.Event; 037import org.ametys.core.observation.Observer; 038import org.ametys.plugins.repository.AmetysObjectResolver; 039import org.ametys.plugins.repository.UnknownAmetysObjectException; 040import org.ametys.plugins.repository.jcr.JCRAmetysObject; 041import org.ametys.plugins.repository.provider.RequestAttributeWorkspaceSelector; 042import org.ametys.runtime.plugin.component.AbstractLogEnabled; 043import org.ametys.web.WebConstants; 044import org.ametys.web.indexing.solr.SolrPageIndexer; 045import org.ametys.web.repository.page.Page; 046import org.ametys.web.repository.page.jcr.DefaultZone; 047 048/** 049 * Abstract {@link Observer} for synchronizing the live solr index. 050 */ 051public abstract class AbstractLiveSolrObserver extends AbstractLogEnabled implements IndexingObserver, Contextualizable, Serviceable 052{ 053 /** The Avalon context. */ 054 protected Context _context; 055 /** The ametys object resolver. */ 056 protected AmetysObjectResolver _resolver; 057 /** The Solr indexer. */ 058 protected SolrIndexer _solrIndexer; 059 /** The Solr page indexer. */ 060 protected SolrPageIndexer _solrPageIndexer; 061 062 @Override 063 public void contextualize(Context context) throws ContextException 064 { 065 _context = context; 066 } 067 068 @Override 069 public void service(ServiceManager manager) throws ServiceException 070 { 071 _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE); 072 _solrIndexer = (SolrIndexer) manager.lookup(SolrIndexer.ROLE); 073 _solrPageIndexer = (SolrPageIndexer) manager.lookup(SolrPageIndexer.ROLE); 074 } 075 076 @Override 077 public int getPriority() 078 { 079 // Will be processed after live synchronization observers 080 return MAX_PRIORITY + 3000; 081 } 082 083 @Override 084 public void observe(Event event, Map<String, Object> transientVars) throws Exception 085 { 086 if (ObserverHelper.isNotSuspendedObservationForIndexation()) 087 { 088 Request request = ContextHelper.getRequest(_context); 089 090 // Retrieve current workspace 091 String currentWsp = RequestAttributeWorkspaceSelector.getForcedWorkspace(request); 092 093 try 094 { 095 // Use live workspace 096 RequestAttributeWorkspaceSelector.setForcedWorkspace(request, WebConstants.LIVE_WORKSPACE); 097 098 _updateIndex(event, transientVars); 099 } 100 catch (Exception e) 101 { 102 getLogger().error("Unable to create or update index for event: " + event, e); 103 } 104 finally 105 { 106 // Restore context 107 RequestAttributeWorkspaceSelector.setForcedWorkspace(request, currentWsp); 108 } 109 } 110 } 111 112 /** 113 * Update the index from the event observed. 114 * @param event the event. 115 * @param transientVars the transient vars passed from one Observer to another when processing a single Event. 116 * @throws Exception if an error occurs. 117 */ 118 protected abstract void _updateIndex(Event event, Map<String, Object> transientVars) throws Exception; 119 120 ///////////////////////////////////////////////////////////////////////// 121 122 /** 123 * Updates Solr page documents associated with a content. 124 * @param contentId the content id. 125 * @throws Exception if an error occurs. 126 */ 127 protected void _updatePageDocumentsForContent(String contentId) throws Exception 128 { 129 Request request = ContextHelper.getRequest(_context); 130 131 // Retrieve current workspace 132 String currentWsp = RequestAttributeWorkspaceSelector.getForcedWorkspace(request); 133 134 try 135 { 136 // Use live workspace 137 RequestAttributeWorkspaceSelector.setForcedWorkspace(request, WebConstants.LIVE_WORKSPACE); 138 Content liveContent = null; 139 140 try 141 { 142 // Retrieve page in the live workspace 143 liveContent = _resolver.resolveById(contentId); 144 } 145 catch (UnknownAmetysObjectException e) 146 { 147 // Content is not in the live workspace 148 } 149 150 if (liveContent != null) 151 { 152 PropertyIterator itReferences = ((JCRAmetysObject) liveContent).getNode().getReferences(); 153 154 try 155 { 156 while (itReferences.hasNext()) 157 { 158 Node refererNode = itReferences.nextProperty().getParent(); 159 160 if (refererNode.getPrimaryNodeType().getName().equals(DefaultZone.ZONEITEM_NODE_NAME)) 161 { 162 Node pageNode = refererNode.getParent().getParent().getParent().getParent(); 163 Page livePage = _resolver.resolve(pageNode, false); 164 165 if (getLogger().isInfoEnabled()) 166 { 167 getLogger().info("Updating solr document with id: " + livePage.getId()); 168 } 169 170 // Updates the document by first deleting it 171 _solrPageIndexer.indexPage(livePage.getId(), WebConstants.LIVE_WORKSPACE, false, false); 172 } 173 } 174 } 175 catch (Exception e) 176 { 177 getLogger().error("Error indexing page documents for content " + contentId, e); 178 } 179 } 180 } 181 finally 182 { 183 // Restore context 184 RequestAttributeWorkspaceSelector.setForcedWorkspace(request, currentWsp); 185 } 186 } 187 188 /** 189 * Deletes Solr page documents associated with a content. 190 * @param contentId the content id. 191 * @throws Exception if an error occurs. 192 */ 193 protected void _deletePageDocumentsForContent(String contentId) throws Exception 194 { 195 Request request = ContextHelper.getRequest(_context); 196 197 // Retrieve current workspace 198 String currentWsp = RequestAttributeWorkspaceSelector.getForcedWorkspace(request); 199 200 try 201 { 202 // Use live workspace 203 RequestAttributeWorkspaceSelector.setForcedWorkspace(request, WebConstants.LIVE_WORKSPACE); 204 Content liveContent = null; 205 206 try 207 { 208 // Retrieve page in the live workspace 209 liveContent = _resolver.resolveById(contentId); 210 } 211 catch (UnknownAmetysObjectException e) 212 { 213 // Page is not synchronized 214 } 215 216 if (liveContent != null) 217 { 218 PropertyIterator itReferences = ((JCRAmetysObject) liveContent).getNode().getReferences(); 219 220 try 221 { 222 while (itReferences.hasNext()) 223 { 224 Node refererNode = itReferences.nextProperty().getParent(); 225 226 if (refererNode.getPrimaryNodeType().getName().equals(DefaultZone.ZONEITEM_NODE_NAME)) 227 { 228 Node pageNode = refererNode.getParent().getParent().getParent().getParent(); 229 Page livePage = _resolver.resolve(pageNode, false); 230 231 if (getLogger().isInfoEnabled()) 232 { 233 getLogger().info("Updating solr document with id: " + livePage.getId()); 234 } 235 236 // Delete the page document. 237 _solrPageIndexer.unindexPage(livePage.getId(), WebConstants.LIVE_WORKSPACE, true, true); 238 } 239 } 240 } 241 catch (Exception e) 242 { 243 getLogger().error("Error unindexing page documents for content " + contentId, e); 244 } 245 } 246 } 247 finally 248 { 249 // Restore context 250 RequestAttributeWorkspaceSelector.setForcedWorkspace(request, currentWsp); 251 } 252 } 253 254 /////////////////////////////////////////////////////////////////////////// 255 256 /** 257 * Updates a Solr document referencing a page. 258 * @param pageId the page id. 259 * @throws Exception if an error occurs. 260 */ 261 protected void _updatePageDocument(String pageId) throws Exception 262 { 263 _updatePageDocument(pageId, false); 264 } 265 266 /** 267 * Updates a Solr document referencing a page. 268 * @param pageId the page id. 269 * @param indexRecursively to also process children pages. 270 * @throws Exception if an error occurs. 271 */ 272 protected void _updatePageDocument(String pageId, boolean indexRecursively) throws Exception 273 { 274 _solrPageIndexer.reindexPage(pageId, WebConstants.LIVE_WORKSPACE, indexRecursively, false); 275 } 276 277 /** 278 * Returns the page in the live workspace corresponding to a given id. 279 * @param pageId the page id. 280 * @return the page in the live workspace or null if not present. 281 */ 282 protected Page _getPageInLive(String pageId) 283 { 284 Request request = ContextHelper.getRequest(_context); 285 286 // Retrieve current workspace 287 String currentWsp = RequestAttributeWorkspaceSelector.getForcedWorkspace(request); 288 289 try 290 { 291 // Use live workspace 292 RequestAttributeWorkspaceSelector.setForcedWorkspace(request, WebConstants.LIVE_WORKSPACE); 293 Page livePage = null; 294 295 try 296 { 297 // Retrieve page in the live workspace 298 livePage = _resolver.resolveById(pageId); 299 } 300 catch (UnknownAmetysObjectException e) 301 { 302 // Page is not synchronized 303 } 304 305 return livePage; 306 } 307 finally 308 { 309 // Restore context 310 RequestAttributeWorkspaceSelector.setForcedWorkspace(request, currentWsp); 311 } 312 } 313 314}