001/* 002 * Copyright 2020 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.List; 019import java.util.Map; 020 021import org.apache.avalon.framework.context.Context; 022import org.apache.avalon.framework.context.ContextException; 023import org.apache.avalon.framework.context.Contextualizable; 024import org.apache.avalon.framework.service.ServiceException; 025import org.apache.avalon.framework.service.ServiceManager; 026import org.apache.avalon.framework.service.Serviceable; 027import org.apache.cocoon.components.ContextHelper; 028import org.apache.cocoon.environment.Request; 029import org.apache.commons.lang.StringUtils; 030 031import org.ametys.cms.content.indexing.solr.observation.ObserverHelper; 032import org.ametys.cms.indexing.IndexingObserver; 033import org.ametys.cms.repository.Content; 034import org.ametys.core.observation.Event; 035import org.ametys.core.observation.Observer; 036import org.ametys.plugins.repository.AmetysObjectResolver; 037import org.ametys.plugins.repository.provider.RequestAttributeWorkspaceSelector; 038import org.ametys.runtime.plugin.component.AbstractLogEnabled; 039import org.ametys.web.ObservationConstants; 040import org.ametys.web.WebConstants; 041import org.ametys.web.repository.content.WebContent; 042import org.ametys.web.repository.page.Page; 043 044/** 045 * Observes when a page changed, moved or deleted and test if it's in the live 046 */ 047public class ContentOrphanStatusPart1Observer extends AbstractLogEnabled implements IndexingObserver, Serviceable, Contextualizable 048{ 049 /** Transient variables to get the id of pages that was in live before live synchronization process */ 050 public static final String PAGES_IN_LIVE_BEFORE_SYNCHRONIZATION = ContentOrphanStatusPart1Observer.class.getName() + "$pagesInLive"; 051 052 /** The Ametys object resolver */ 053 protected AmetysObjectResolver _resolver; 054 /** The avalon context */ 055 protected Context _context; 056 057 @Override 058 public void service(ServiceManager manager) throws ServiceException 059 { 060 _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE); 061 } 062 063 @Override 064 public void contextualize(Context context) throws ContextException 065 { 066 _context = context; 067 } 068 069 @Override 070 public boolean supports(Event event) 071 { 072 return event.getId().equals(ObservationConstants.EVENT_PAGE_CHANGED) 073 || event.getId().equals(ObservationConstants.EVENT_PAGE_MOVED) 074 || event.getId().equals(ObservationConstants.EVENT_PAGE_DELETED) 075 || event.getId().equals(org.ametys.cms.ObservationConstants.EVENT_CONTENT_UNTAG_LIVE) 076 || event.getId().equals(org.ametys.cms.ObservationConstants.EVENT_CONTENT_VALIDATED); 077 } 078 079 @Override 080 public int getPriority() 081 { 082 // Will be processed BEFORE live synchronization observers, since pages have to be present in live to be unindexed. 083 return Observer.MAX_PRIORITY + 500; 084 } 085 086 @Override 087 public void observe(Event event, Map<String, Object> transientVars) throws Exception 088 { 089 if (ObserverHelper.isNotSuspendedObservationForIndexation()) 090 { 091 List<String> livePageIds = _getPageIds(event) 092 .stream() 093 .filter(this::_isInLive) 094 .toList(); 095 096 transientVars.put(PAGES_IN_LIVE_BEFORE_SYNCHRONIZATION, livePageIds); 097 } 098 } 099 100 private List<String> _getPageIds(Event event) 101 { 102 String pageId = (String) event.getArguments().get(ObservationConstants.ARGS_PAGE_ID); 103 if (StringUtils.isNotEmpty(pageId)) 104 { 105 return List.of(pageId); 106 } 107 108 Page page = (Page) event.getArguments().get(ObservationConstants.ARGS_PAGE); 109 if (page != null) 110 { 111 return List.of(page.getId()); 112 } 113 114 Content content = (Content) event.getArguments().get(org.ametys.cms.ObservationConstants.ARGS_CONTENT); 115 if (content != null && content instanceof WebContent webContent) 116 { 117 return webContent.getReferencingPages() 118 .stream() 119 .map(Page::getId) 120 .toList(); 121 } 122 123 return List.of(); 124 } 125 126 private boolean _isInLive(String pageId) 127 { 128 Request request = ContextHelper.getRequest(_context); 129 String currentWsp = RequestAttributeWorkspaceSelector.getForcedWorkspace(request); 130 try 131 { 132 // Force the workspace. 133 RequestAttributeWorkspaceSelector.setForcedWorkspace(request, WebConstants.LIVE_WORKSPACE); 134 return _resolver.hasAmetysObjectForId(pageId); 135 } 136 finally 137 { 138 // Restore workspace 139 RequestAttributeWorkspaceSelector.setForcedWorkspace(request, currentWsp); 140 } 141 } 142}