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