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 */ 016 017package org.ametys.plugins.ugc.observation; 018 019import java.util.Map; 020import java.util.Optional; 021 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.environment.Context; 028 029import org.ametys.cms.ObservationConstants; 030import org.ametys.cms.contenttype.ContentTypesHelper; 031import org.ametys.cms.repository.Content; 032import org.ametys.core.observation.Event; 033import org.ametys.core.observation.Observer; 034import org.ametys.plugins.repository.AmetysObjectIterable; 035import org.ametys.plugins.repository.AmetysObjectResolver; 036import org.ametys.plugins.repository.query.expression.Expression; 037import org.ametys.plugins.repository.query.expression.VirtualFactoryExpression; 038import org.ametys.plugins.ugc.page.UGCPage; 039import org.ametys.plugins.ugc.page.UGCPageHandler; 040import org.ametys.plugins.ugc.page.VirtualUGCPageFactory; 041import org.ametys.runtime.plugin.component.AbstractLogEnabled; 042import org.ametys.web.cache.pageelement.PageElementCache; 043import org.ametys.web.repository.page.Page; 044import org.ametys.web.repository.page.PageQueryHelper; 045import org.ametys.web.repository.page.Zone; 046import org.ametys.web.repository.page.ZoneItem; 047 048/** 049 * Abstract {@link Observer} for observing validation of UGC content. 050 */ 051public abstract class AbstractContentObserver extends AbstractLogEnabled implements Observer, Serviceable, Contextualizable 052{ 053 /** The context. */ 054 protected org.apache.avalon.framework.context.Context _context; 055 /** Cocoon context. */ 056 protected Context _cocoonContext; 057 /** Ametys object resolver. */ 058 protected AmetysObjectResolver _resolver; 059 /** The content type helper */ 060 protected ContentTypesHelper _contentTypeHelper; 061 /** The page element cache */ 062 protected PageElementCache _zoneItemCache; 063 /** The UGC page handler */ 064 protected UGCPageHandler _ugcPageHandler; 065 066 @Override 067 public void contextualize(org.apache.avalon.framework.context.Context context) throws ContextException 068 { 069 _context = context; 070 _cocoonContext = (Context) context.get(org.apache.cocoon.Constants.CONTEXT_ENVIRONMENT_CONTEXT); 071 } 072 073 @Override 074 public void service(ServiceManager manager) throws ServiceException 075 { 076 _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE); 077 _contentTypeHelper = (ContentTypesHelper) manager.lookup(ContentTypesHelper.ROLE); 078 _zoneItemCache = (PageElementCache) manager.lookup(PageElementCache.ROLE + "/zoneItem"); 079 _ugcPageHandler = (UGCPageHandler) manager.lookup(UGCPageHandler.ROLE); 080 } 081 082 @Override 083 public void observe(Event event, Map<String, Object> transientVars) 084 { 085 try 086 { 087 Content content = _getTarget(event); 088 AmetysObjectIterable<Page> rootPages = _getUGCRootPages(); 089 if (!rootPages.iterator().hasNext()) 090 { 091 getLogger().debug("There's no UGC root page, nothing to invalidate"); 092 return; 093 } 094 095 for (Page rootPage : rootPages) 096 { 097 if (_isUGCContent(content, rootPage)) 098 { 099 _internalObserve(event, rootPage, content); 100 } 101 } 102 } 103 catch (Exception e) 104 { 105 getLogger().error("Unable to observe event: " + event, e); 106 } 107 } 108 109 /** 110 * Do the actual work. 111 * @param event the observation event. 112 * @param rootPage the page holding the UGC content pages 113 * @param content the UGC content. 114 */ 115 protected abstract void _internalObserve(Event event, Page rootPage, Content content); 116 117 /** 118 * Get the UGC root pages 119 * @return the UGC root pages 120 */ 121 protected AmetysObjectIterable<Page> _getUGCRootPages () 122 { 123 Expression expression = new VirtualFactoryExpression(VirtualUGCPageFactory.class.getName()); 124 String query = PageQueryHelper.getPageXPathQuery(null, null, null, expression, null); 125 126 return _resolver.query(query); 127 } 128 129 /** 130 * Retrieve the target of the observer 131 * @param event The event 132 * @return The target 133 * @throws Exception if failed to get content 134 */ 135 protected Content _getTarget(Event event) throws Exception 136 { 137 return (Content) event.getArguments().get(ObservationConstants.ARGS_CONTENT); 138 } 139 140 /** 141 * Return true if the content is a UGC content 142 * @param content the content 143 * @param rootPage the root page 144 * @return true if the content is a UGC content 145 */ 146 protected boolean _isUGCContent(Content content, Page rootPage) 147 { 148 String contentTypeId = _ugcPageHandler.getContentTypeId(rootPage); 149 return content != null && _contentTypeHelper.isInstanceOf(content, contentTypeId); 150 } 151 152 /** 153 * Remove zone item cache 154 * @param rootPage the root page 155 * @param content the content 156 * @param workspace the workspace 157 */ 158 protected void _removeZoneItemCache(Page rootPage, Content content, String workspace) 159 { 160 if (_isUGCContent(content, rootPage)) 161 { 162 Optional<UGCPage> ugcPage = _ugcPageHandler.getUgcPage(rootPage, content); 163 if (ugcPage.isPresent()) 164 { 165 AmetysObjectIterable< ? extends Zone> zones = ugcPage.get().getZones(); 166 for (Zone zone : zones) 167 { 168 for (ZoneItem zoneItem : zone.getZoneItems()) 169 { 170 _zoneItemCache.removeItem(workspace, rootPage.getSiteName(), "CONTENT", zoneItem.getId()); 171 } 172 } 173 } 174 } 175 } 176}