001/* 002 * Copyright 2017 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.plugins.odfweb.restrictions; 017 018import java.io.File; 019import java.io.FileInputStream; 020import java.io.InputStream; 021import java.util.ArrayList; 022import java.util.Collections; 023import java.util.HashMap; 024import java.util.List; 025import java.util.Map; 026import java.util.Set; 027 028import org.apache.avalon.framework.activity.Disposable; 029import org.apache.avalon.framework.component.Component; 030import org.apache.avalon.framework.configuration.Configuration; 031import org.apache.avalon.framework.configuration.ConfigurationException; 032import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder; 033import org.apache.avalon.framework.context.Context; 034import org.apache.avalon.framework.context.ContextException; 035import org.apache.avalon.framework.context.Contextualizable; 036import org.apache.avalon.framework.logger.AbstractLogEnabled; 037import org.apache.avalon.framework.service.ServiceException; 038import org.apache.avalon.framework.service.ServiceManager; 039import org.apache.avalon.framework.service.Serviceable; 040import org.apache.cocoon.Constants; 041import org.apache.cocoon.components.ContextHelper; 042import org.apache.cocoon.environment.Request; 043import org.apache.commons.lang.StringUtils; 044 045import org.ametys.cms.content.ContentHelper; 046import org.ametys.cms.contenttype.ContentTypeExtensionPoint; 047import org.ametys.core.ui.Callable; 048import org.ametys.odf.orgunit.OrgUnit; 049import org.ametys.odf.orgunit.RootOrgUnitProvider; 050import org.ametys.plugins.odfweb.restrictions.rules.OdfAndRestrictionRule; 051import org.ametys.plugins.odfweb.restrictions.rules.OdfMetadataRestrictionRule; 052import org.ametys.plugins.odfweb.restrictions.rules.OdfNotRestrictionRule; 053import org.ametys.plugins.odfweb.restrictions.rules.OdfOrRestrictionRule; 054import org.ametys.plugins.odfweb.restrictions.rules.OdfOrgunitRestrictionRule; 055import org.ametys.plugins.odfweb.restrictions.rules.OdfRestrictionRule; 056import org.ametys.plugins.repository.AmetysObjectResolver; 057import org.ametys.plugins.repository.provider.RequestAttributeWorkspaceSelector; 058import org.ametys.runtime.i18n.I18nizableText; 059import org.ametys.web.repository.page.Page; 060import org.ametys.web.site.SiteConfigurationExtensionPoint; 061 062/** 063 * Component able to handle program restrictions related to the "odf-restrictions" site parameter. 064 */ 065public class OdfProgramRestrictionManager extends AbstractLogEnabled implements Component, Serviceable, Contextualizable, Disposable 066{ 067 /** The avalon role. */ 068 public static final String ROLE = OdfProgramRestrictionManager.class.getName(); 069 070 /** Site configuration extension point */ 071 protected SiteConfigurationExtensionPoint _scep; 072 073 /** The content type extension point. */ 074 protected ContentTypeExtensionPoint _cTypeEP; 075 076 /** Ametys object resolver */ 077 protected AmetysObjectResolver _resolver; 078 079 /** Root orgunit provider */ 080 protected RootOrgUnitProvider _rootOrgUnitProvider; 081 082 /** Cocoon context */ 083 protected org.apache.cocoon.environment.Context _cocoonContext; 084 085 /** The available odf restrictions */ 086 protected Map<String, OdfProgramRestriction> _restrictions; 087 088 /** Content helper */ 089 protected ContentHelper _contentHelper; 090 091 private Context _context; 092 093 @Override 094 public void service(ServiceManager serviceManager) throws ServiceException 095 { 096 _scep = (SiteConfigurationExtensionPoint) serviceManager.lookup(SiteConfigurationExtensionPoint.ROLE); 097 _cTypeEP = (ContentTypeExtensionPoint) serviceManager.lookup(ContentTypeExtensionPoint.ROLE); 098 _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE); 099 _rootOrgUnitProvider = (RootOrgUnitProvider) serviceManager.lookup(RootOrgUnitProvider.ROLE); 100 } 101 102 @Override 103 public void contextualize(Context context) throws ContextException 104 { 105 _context = context; 106 _cocoonContext = (org.apache.cocoon.environment.Context) context.get(Constants.CONTEXT_ENVIRONMENT_CONTEXT); 107 } 108 109 @Override 110 public void dispose() 111 { 112 _restrictions = null; 113 } 114 115 /** 116 * Retrieves the available restrictions 117 * @return The map of restriction, where keys are restriction ids. 118 */ 119 public Map<String, OdfProgramRestriction> getRestrictions() 120 { 121 // Lazy initialize restrictions because orgunit restrictions cannot be 122 // resolved during the initialization of the component 123 if (_restrictions == null) 124 { 125 _readRestrictionConfigurationFile(); 126 } 127 128 return _restrictions; 129 } 130 131 /** 132 * Get the ODF restriction for the given ODF root page 133 * @param odfRootPage The ODF root page 134 * @return The restriction or <code>null</code> 135 */ 136 public OdfProgramRestriction getRestriction(Page odfRootPage) 137 { 138 String restrictionId = _scep.getValueAsString(odfRootPage.getSiteName(), "odf-restrictions"); 139 if (StringUtils.isNotEmpty(restrictionId)) 140 { 141 return getRestrictions().get(restrictionId); 142 } 143 144 return null; 145 } 146 147 /** 148 * Indicate is there is any restriction for this root page 149 * @param rootPage odf root page 150 * @return true if it is the case 151 */ 152 public boolean hasRestrictions(Page rootPage) 153 { 154 String restrictionId = _scep.getValueAsString(rootPage.getSiteName(), "odf-restrictions"); 155 return StringUtils.isNotEmpty(restrictionId) ? getRestrictions().containsKey(restrictionId) : false; 156 } 157 158 /** 159 * Indicate is there is any restriction related to orgunit for this root page 160 * @param rootPage odf root page 161 * @return true if it is the case 162 */ 163 public boolean hasOrgunitRestrictions(Page rootPage) 164 { 165 String restrictionId = _scep.getValueAsString(rootPage.getSiteName(), "odf-restrictions"); 166 if (StringUtils.isNotEmpty(restrictionId)) 167 { 168 OdfProgramRestriction odfProgramRestriction = getRestrictions().get(restrictionId); 169 return odfProgramRestriction.hasOrgunitRestrictions(); 170 } 171 172 return false; 173 } 174 175 /** 176 * Get the id of the restriction root orgunit 177 * @param siteName the site name 178 * @return the id of the restriction root orgunit 179 */ 180 @Callable 181 public String getRestrictionRootOrgUnitId(String siteName) 182 { 183 String odfRootId = null; 184 185 String restrictionId = _scep.getValueAsString(siteName, "odf-restrictions"); 186 if (StringUtils.isNotEmpty(restrictionId)) 187 { 188 OdfProgramRestriction odfProgramRestriction = getRestrictions().get(restrictionId); 189 if (odfProgramRestriction != null && odfProgramRestriction.hasOrgunitRestrictions()) 190 { 191 odfRootId = odfProgramRestriction.getId(); 192 } 193 } 194 195 if (StringUtils.isBlank(odfRootId)) 196 { 197 odfRootId = _rootOrgUnitProvider.getRootId(); 198 } 199 200 return odfRootId; 201 } 202 203 /** 204 * Configured the restrictions from the XML configuration file 205 */ 206 protected void _readRestrictionConfigurationFile() 207 { 208 _restrictions = new HashMap<>(); 209 210 File restrictionFile = new File (_cocoonContext.getRealPath("/WEB-INF/param/odf-restrictions.xml")); 211 212 if (restrictionFile.exists()) 213 { 214 try (InputStream is = new FileInputStream(restrictionFile);) 215 { 216 Configuration cfg = new DefaultConfigurationBuilder().build(is); 217 218 Configuration[] restrictionConfs = cfg.getChildren("restriction"); 219 for (Configuration restrictionConf : restrictionConfs) 220 { 221 String id = restrictionConf.getAttribute("id"); 222 I18nizableText label = _configureI18nizableText(restrictionConf, "label", "", "application"); 223 List<OdfRestrictionRule> rules = _configureRestrictionRules(restrictionConf.getChild("rules")); 224 225 _restrictions.put(id, new OdfProgramRestriction(id, label, rules)); 226 } 227 228 Configuration orgunitConf = cfg.getChild("orgunits", false); 229 if (orgunitConf != null) 230 { 231 _addDefaultOrgunitRestrictions(); 232 } 233 } 234 catch (Exception e) 235 { 236 getLogger().error("Cannot read the configuration file located at /WEB-INF/param/odf-restrictions.xml. Reverting to default.", e); 237 _restrictions.clear(); 238 _addDefaultOrgunitRestrictions(); 239 } 240 } 241 else 242 { 243 _addDefaultOrgunitRestrictions(); 244 } 245 } 246 247 private I18nizableText _configureI18nizableText(Configuration config, String name, String defaultValue, String defaultCatalog) 248 { 249 Configuration textConfig = config.getChild(name); 250 boolean i18nSupported = textConfig.getAttributeAsBoolean("i18n", false); 251 String text = textConfig.getValue(defaultValue); 252 253 if (i18nSupported) 254 { 255 String catalogue = textConfig.getAttribute("catalogue", defaultCatalog); 256 return new I18nizableText(catalogue, text); 257 } 258 else 259 { 260 return new I18nizableText(text); 261 } 262 } 263 264 /** 265 * Create a list of rules from configuration nodes 266 * @param rulesConf Array of configuration node that represents the set of rules 267 * @return list of rules 268 * @throws ConfigurationException if a configuration error is encountered 269 */ 270 protected List<OdfRestrictionRule> _configureRestrictionRules(Configuration rulesConf) throws ConfigurationException 271 { 272 List<OdfRestrictionRule> rules = new ArrayList<>(); 273 274 for (Configuration ruleConf : rulesConf.getChildren()) 275 { 276 rules.add(_configureRestrictionRule(ruleConf)); 277 } 278 279 return rules; 280 } 281 282 /** 283 * Configure a restriction rule from a configuration node 284 * @param ruleConf The configuration node representing the rule 285 * @return The odf restriction rule 286 * @throws ConfigurationException if a configuration error is encountered 287 */ 288 protected OdfRestrictionRule _configureRestrictionRule(Configuration ruleConf) throws ConfigurationException 289 { 290 String name = ruleConf.getName(); 291 292 if ("metadata".equals(name)) 293 { 294 String metadataPath = ruleConf.getAttribute("name"); 295 String metadataValue = ruleConf.getAttribute("value"); 296 return new OdfMetadataRestrictionRule(_contentHelper, metadataPath, metadataValue); 297 } 298 else if ("orgunit".equals(name)) 299 { 300 String orgunitId = ruleConf.getAttribute("id", null); 301 302 if (StringUtils.isEmpty(orgunitId)) 303 { 304 throw new ConfigurationException("Expecting 'id' attribute for orgunit restriction rule."); 305 } 306 307 return new OdfOrgunitRestrictionRule(_rootOrgUnitProvider, orgunitId); 308 } 309 else if ("and".equals(name)) 310 { 311 List<OdfRestrictionRule> childRules = _configureRestrictionRules(ruleConf); 312 return new OdfAndRestrictionRule(childRules); 313 } 314 else if ("or".equals(name)) 315 { 316 List<OdfRestrictionRule> childRules = _configureRestrictionRules(ruleConf); 317 return new OdfOrRestrictionRule(childRules); 318 } 319 else if ("not".equals(name)) 320 { 321 List<OdfRestrictionRule> childRules = _configureRestrictionRules(ruleConf); 322 return new OdfNotRestrictionRule(childRules); 323 } 324 325 throw new ConfigurationException("Unknow node name in restriction configuration : " + name); 326 } 327 328 private void _addDefaultOrgunitRestrictions() 329 { 330 Request request = ContextHelper.getRequest(_context); 331 String currentWsp = RequestAttributeWorkspaceSelector.getForcedWorkspace(request); 332 333 try 334 { 335 // Force default workspace 336 RequestAttributeWorkspaceSelector.setForcedWorkspace(request, null); 337 338 String rootOrgunitId = _rootOrgUnitProvider.getRootId(); 339 Set<String> orgunitIds = _rootOrgUnitProvider.getChildOrgUnitIds(rootOrgunitId, true); 340 orgunitIds.add(rootOrgunitId); 341 342 for (String id : orgunitIds) 343 { 344 if (!StringUtils.equals(id, rootOrgunitId)) 345 { 346 OrgUnit orgunit = _resolver.resolveById(id); 347 348 OdfRestrictionRule rule = new OdfOrgunitRestrictionRule(_rootOrgUnitProvider, id); 349 OdfProgramRestriction restriction = new OdfProgramRestriction(id, new I18nizableText(orgunit.getTitle()), Collections.singletonList(rule)); 350 351 _restrictions.put(id, restriction); 352 } 353 } 354 } 355 finally 356 { 357 // Restore workspace 358 RequestAttributeWorkspaceSelector.setForcedWorkspace(request, currentWsp); 359 } 360 } 361}