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