001/* 002 * Copyright 2016 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.userdirectory.observation; 018 019import java.util.Map; 020 021import org.apache.avalon.framework.context.ContextException; 022import org.apache.avalon.framework.context.Contextualizable; 023import org.apache.avalon.framework.service.ServiceException; 024import org.apache.avalon.framework.service.ServiceManager; 025import org.apache.avalon.framework.service.Serviceable; 026import org.apache.cocoon.environment.Context; 027import org.apache.commons.lang3.ArrayUtils; 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.userdirectory.UserDirectoryHelper; 039import org.ametys.plugins.userdirectory.UserDirectoryPageHandler; 040import org.ametys.plugins.userdirectory.page.OrgUnitPage; 041import org.ametys.plugins.userdirectory.page.OrganisationChartPageResolver; 042import org.ametys.plugins.userdirectory.page.UserDirectoryPageResolver; 043import org.ametys.plugins.userdirectory.page.UserPage; 044import org.ametys.plugins.userdirectory.page.VirtualOrganisationChartPageFactory; 045import org.ametys.plugins.userdirectory.page.VirtualUserDirectoryPageFactory; 046import org.ametys.runtime.plugin.component.AbstractLogEnabled; 047import org.ametys.web.cache.pageelement.PageElementCache; 048import org.ametys.web.repository.page.Page; 049import org.ametys.web.repository.page.PageQueryHelper; 050import org.ametys.web.repository.page.Zone; 051import org.ametys.web.repository.page.ZoneItem; 052import org.ametys.web.repository.page.ZoneItem.ZoneType; 053 054/** 055 * Abstract {@link Observer} for observing validation of User content. 056 */ 057public abstract class AbstractContentObserver extends AbstractLogEnabled implements Observer, Serviceable, Contextualizable 058{ 059 /** The context. */ 060 protected org.apache.avalon.framework.context.Context _context; 061 /** Cocoon context. */ 062 protected Context _cocoonContext; 063 /** Ametys object resolver. */ 064 protected AmetysObjectResolver _resolver; 065 /** The content type helper */ 066 protected ContentTypesHelper _contentTypeHelper; 067 /** The page element cache */ 068 protected PageElementCache _zoneItemCache; 069 /** The resolver for user directory pages */ 070 protected UserDirectoryPageResolver _userDirectoryPageResolver; 071 /** The resolver for ud orgunits pages */ 072 protected OrganisationChartPageResolver _organisationChartPageResolver; 073 074 @Override 075 public void contextualize(org.apache.avalon.framework.context.Context context) throws ContextException 076 { 077 _context = context; 078 _cocoonContext = (Context) context.get(org.apache.cocoon.Constants.CONTEXT_ENVIRONMENT_CONTEXT); 079 } 080 081 @Override 082 public void service(ServiceManager manager) throws ServiceException 083 { 084 _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE); 085 _contentTypeHelper = (ContentTypesHelper) manager.lookup(ContentTypesHelper.ROLE); 086 _zoneItemCache = (PageElementCache) manager.lookup(PageElementCache.ROLE + "/zoneItem"); 087 _userDirectoryPageResolver = (UserDirectoryPageResolver) manager.lookup(UserDirectoryPageResolver.ROLE); 088 _organisationChartPageResolver = (OrganisationChartPageResolver) manager.lookup(OrganisationChartPageResolver.ROLE); 089 } 090 091 @Override 092 public void observe(Event event, Map<String, Object> transientVars) 093 { 094 try 095 { 096 Content content = _getTarget(event); 097 if (_isUserContent(content)) 098 { 099 AmetysObjectIterable<Page> rootPages = _getUserRootPages (); 100 if (!rootPages.iterator().hasNext()) 101 { 102 getLogger().debug("There's no user root page, nothing to invalidate"); 103 return; 104 } 105 106 for (Page rootPage : rootPages) 107 { 108 String cType = rootPage.getValue(UserDirectoryPageHandler.CONTENT_TYPE_DATA_NAME); 109 if (ArrayUtils.contains(content.getTypes(), cType)) 110 { 111 _internalObserve(event, rootPage, content); 112 } 113 } 114 } 115 else if (_isOrgUnitContent(content)) 116 { 117 AmetysObjectIterable<Page> rootPages = _getOrgUnitRootPages (); 118 if (!rootPages.iterator().hasNext()) 119 { 120 getLogger().debug("There's no orgUnit root page, nothing to invalidate"); 121 return; 122 } 123 124 for (Page rootPage : rootPages) 125 { 126 _internalObserve(event, rootPage, content); 127 } 128 } 129 } 130 catch (Exception e) 131 { 132 getLogger().error("Unable to observe event: " + event, e); 133 } 134 } 135 136 /** 137 * Do the actual work. 138 * @param event the observation event. 139 * @param rootUsersPage the page holding the virtual user pages 140 * @param userContent a list containing all impacted user contents. 141 */ 142 protected abstract void _internalObserve(Event event, Page rootUsersPage, Content userContent); 143 144 /** 145 * Get the user root pages 146 * @return the user root pages 147 */ 148 protected AmetysObjectIterable<Page> _getUserRootPages () 149 { 150 Expression expression = new VirtualFactoryExpression(VirtualUserDirectoryPageFactory.class.getName()); 151 String query = PageQueryHelper.getPageXPathQuery(null, null, null, expression, null); 152 153 return _resolver.query(query); 154 } 155 156 /** 157 * Get the orgUnit root pages 158 * @return the orgUnit root pages 159 */ 160 protected AmetysObjectIterable<Page> _getOrgUnitRootPages () 161 { 162 Expression expression = new VirtualFactoryExpression(VirtualOrganisationChartPageFactory.class.getName()); 163 String query = PageQueryHelper.getPageXPathQuery(null, null, null, expression, null); 164 165 return _resolver.query(query); 166 } 167 168 /** 169 * Retrieve the target of the observer 170 * @param event The event 171 * @return The target 172 * @throws Exception if failed to get content 173 */ 174 protected Content _getTarget(Event event) throws Exception 175 { 176 return (Content) event.getArguments().get(ObservationConstants.ARGS_CONTENT); 177 } 178 179 /** 180 * Return true if the content is a user content 181 * @param content the content 182 * @return true if the content is a user content 183 */ 184 protected boolean _isUserContent(Content content) 185 { 186 return content != null && _contentTypeHelper.isInstanceOf(content, UserDirectoryHelper.ABSTRACT_USER_CONTENT_TYPE); 187 } 188 189 /** 190 * Return true if the content is a orgUnit content 191 * @param content the content 192 * @return true if the content is a orgUnit content 193 */ 194 protected boolean _isOrgUnitContent(Content content) 195 { 196 return content != null && _contentTypeHelper.isInstanceOf(content, UserDirectoryHelper.ORGUNIT_CONTENT_TYPE); 197 } 198 199 /** 200 * Remove zone item cache 201 * @param rootPage the root page 202 * @param content the content 203 * @param workspace the workspace 204 */ 205 protected void _removeZoneItemCache(Page rootPage, Content content, String workspace) 206 { 207 if (_isUserContent(content)) 208 { 209 UserPage userPage = _userDirectoryPageResolver.getUserPage(rootPage, content); 210 if (userPage != null) 211 { 212 AmetysObjectIterable< ? extends Zone> zones = userPage.getZones(); 213 for (Zone zone : zones) 214 { 215 for (ZoneItem zoneItem : zone.getZoneItems()) 216 { 217 if (zoneItem.getType().equals(ZoneType.CONTENT)) 218 { 219 _zoneItemCache.removeItem(workspace, rootPage.getSiteName(), "CONTENT", zoneItem.getId()); 220 } 221 } 222 } 223 } 224 } 225 else if (_isOrgUnitContent(content)) 226 { 227 OrgUnitPage orgUnitPage = _organisationChartPageResolver.getOrgUnitPage(rootPage, content); 228 if (orgUnitPage != null) 229 { 230 AmetysObjectIterable< ? extends Zone> zones = orgUnitPage.getZones(); 231 for (Zone zone : zones) 232 { 233 for (ZoneItem zoneItem : zone.getZoneItems()) 234 { 235 if (zoneItem.getType().equals(ZoneType.CONTENT)) 236 { 237 _zoneItemCache.removeItem(workspace, rootPage.getSiteName(), "CONTENT", zoneItem.getId()); 238 } 239 } 240 } 241 } 242 } 243 } 244}