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 */ 016package org.ametys.web.site; 017 018import java.io.File; 019import java.io.FileInputStream; 020import java.io.FileNotFoundException; 021import java.io.IOException; 022import java.io.InputStream; 023import java.nio.file.Files; 024import java.nio.file.Paths; 025import java.util.ArrayList; 026import java.util.Collection; 027import java.util.HashMap; 028import java.util.HashSet; 029import java.util.List; 030import java.util.Map; 031import java.util.Set; 032import java.util.stream.Collectors; 033 034import org.apache.avalon.framework.service.ServiceException; 035import org.apache.avalon.framework.service.ServiceManager; 036import org.apache.cocoon.ProcessingException; 037import org.apache.cocoon.generation.ServiceableGenerator; 038import org.apache.cocoon.xml.AttributesImpl; 039import org.apache.cocoon.xml.XMLUtils; 040import org.apache.commons.lang3.tuple.Pair; 041import org.apache.excalibur.xml.sax.SAXParser; 042import org.xml.sax.InputSource; 043import org.xml.sax.SAXException; 044 045import org.ametys.core.authentication.CredentialProvider; 046import org.ametys.core.authentication.CredentialProviderFactory; 047import org.ametys.core.authentication.CredentialProviderModel; 048import org.ametys.core.datasource.LDAPDataSourceManager; 049import org.ametys.core.datasource.SQLDataSourceManager; 050import org.ametys.core.user.directory.UserDirectory; 051import org.ametys.core.user.directory.UserDirectoryFactory; 052import org.ametys.core.user.directory.UserDirectoryModel; 053import org.ametys.core.user.population.PopulationContextHelper; 054import org.ametys.core.user.population.UserPopulation; 055import org.ametys.core.user.population.UserPopulationDAO; 056import org.ametys.core.util.IgnoreRootHandler; 057import org.ametys.runtime.config.Config; 058import org.ametys.runtime.model.ElementDefinition; 059import org.ametys.runtime.model.type.ModelItemTypeConstants; 060import org.ametys.web.repository.site.SiteManager; 061 062/** 063 * Sax the datasources files limited to datasources useful for front-office 064 */ 065public class SitesPopulationsGenerator extends ServiceableGenerator 066{ 067 private SiteManager _siteManager; 068 private PopulationContextHelper _populationContextHelper; 069 private UserPopulationDAO _userPopulationDAO; 070 private UserDirectoryFactory _userDirectoryFactory; 071 private CredentialProviderFactory _credentialProviderFactory; 072 private SQLDataSourceManager _sqlDataSourceManager; 073 private LDAPDataSourceManager _ldapDataSourceManager; 074 075 @Override 076 public void service(ServiceManager smanager) throws ServiceException 077 { 078 super.service(smanager); 079 _siteManager = (SiteManager) smanager.lookup(SiteManager.ROLE); 080 _populationContextHelper = (PopulationContextHelper) manager.lookup(PopulationContextHelper.ROLE); 081 _userPopulationDAO = (UserPopulationDAO) manager.lookup(UserPopulationDAO.ROLE); 082 _userDirectoryFactory = (UserDirectoryFactory) manager.lookup(UserDirectoryFactory.ROLE); 083 _credentialProviderFactory = (CredentialProviderFactory) manager.lookup(CredentialProviderFactory.ROLE); 084 _sqlDataSourceManager = (SQLDataSourceManager) manager.lookup(SQLDataSourceManager.ROLE); 085 _ldapDataSourceManager = (LDAPDataSourceManager) manager.lookup(LDAPDataSourceManager.ROLE); 086 } 087 088 public void generate() throws IOException, SAXException, ProcessingException 089 { 090 contentHandler.startDocument(); 091 XMLUtils.startElement(contentHandler, "Populations"); 092 093 _saxUsedStuff(); 094 _saxPopulationFile(); 095 _saxDatabasesFiles(); 096 _saxMonitoringInfo(); 097 _saxCaptchaInfo(); 098 099 XMLUtils.endElement(contentHandler, "Populations"); 100 contentHandler.endDocument(); 101 } 102 103 private void _saxMonitoringInfo() throws SAXException 104 { 105 boolean enabled = Config.getInstance().getValue("cache.monitoring.schedulers.enable"); 106 107 AttributesImpl attrs = new AttributesImpl(); 108 attrs.addCDATAAttribute("enabled", enabled ? "true" : "false"); 109 XMLUtils.startElement(contentHandler, "Monitoring", attrs); 110 111 if (enabled) 112 { 113 String datasourceId = Config.getInstance().getValue("cache.monitoring.datasource.jdbc.pool"); 114 XMLUtils.createElement(contentHandler, "Datasource", _replaceDefaultIds(datasourceId)); 115 } 116 117 XMLUtils.endElement(contentHandler, "Monitoring"); 118 } 119 120 private void _saxCaptchaInfo() throws SAXException 121 { 122 String type = Config.getInstance().getValue("runtime.captcha.type"); 123 String publicKey = Config.getInstance().getValue("runtime.captcha.recaptcha.publickey"); 124 String secretKey = Config.getInstance().getValue("runtime.captcha.recaptcha.secretkey"); 125 126 AttributesImpl attrs = new AttributesImpl(); 127 attrs.addCDATAAttribute("type", type); 128 attrs.addCDATAAttribute("publicKey", publicKey); 129 attrs.addCDATAAttribute("secretKey", secretKey); 130 131 XMLUtils.createElement(contentHandler, "Captcha", attrs); 132 } 133 134 private void _saxDatabasesFiles() throws IOException, SAXException 135 { 136 _saxSQLDatabaseFile(); 137 138 _saxLDAPDatabaseFile(); 139 } 140 141 private void _saxLDAPDatabaseFile() throws SAXException, IOException 142 { 143 XMLUtils.startElement(contentHandler, "LDAPDatasources"); 144 145 File file = _ldapDataSourceManager.getFileConfiguration(); 146 if (file.exists()) 147 { 148 SAXParser saxParser = null; 149 try (InputStream is = new FileInputStream(file)) 150 { 151 saxParser = (SAXParser) manager.lookup(SAXParser.ROLE); 152 saxParser.parse(new InputSource(is), new IgnoreRootHandler(contentHandler)); 153 } 154 catch (FileNotFoundException e) 155 { 156 throw new IOException(e); 157 } 158 catch (ServiceException e) 159 { 160 throw new SAXException("Unable to get a SAX parser", e); 161 } 162 finally 163 { 164 manager.release(saxParser); 165 } 166 } 167 168 XMLUtils.endElement(contentHandler, "LDAPDatasources"); 169 } 170 171 private void _saxSQLDatabaseFile() throws SAXException, IOException 172 { 173 XMLUtils.startElement(contentHandler, "SQLDatasources"); 174 175 File file = _sqlDataSourceManager.getFileConfiguration(); 176 if (file.exists()) 177 { 178 SAXParser saxParser = null; 179 try (InputStream is = new FileInputStream(file)) 180 { 181 saxParser = (SAXParser) manager.lookup(SAXParser.ROLE); 182 saxParser.parse(new InputSource(is), new IgnoreRootHandler(contentHandler)); 183 } 184 catch (FileNotFoundException e) 185 { 186 throw new IOException(e); 187 } 188 catch (ServiceException e) 189 { 190 throw new SAXException("Unable to get a SAX parser", e); 191 } 192 finally 193 { 194 manager.release(saxParser); 195 } 196 } 197 198 XMLUtils.endElement(contentHandler, "SQLDatasources"); 199 } 200 201 private void _saxPopulationFile() throws SAXException, IOException 202 { 203 XMLUtils.startElement(contentHandler, "UserPopulations"); 204 File file = _userPopulationDAO.getConfigurationFile(); 205 206 if (file != null && file.exists()) 207 { 208 SAXParser saxParser = null; 209 try (InputStream is = Files.newInputStream(Paths.get(file.getAbsolutePath()))) 210 { 211 saxParser = (SAXParser) manager.lookup(SAXParser.ROLE); 212 saxParser.parse(new InputSource(is), new IgnoreRootHandler(contentHandler)); 213 } 214 catch (ServiceException e) 215 { 216 throw new SAXException("Unable to get a SAX parser", e); 217 } 218 finally 219 { 220 manager.release(saxParser); 221 } 222 } 223 224 XMLUtils.endElement(contentHandler, "UserPopulations"); 225 } 226 227 private void _saxUsedStuff() throws SAXException 228 { 229 Set<UserPopulation> usedPopulations = _getPopulationsUsedBySites(); 230 231 XMLUtils.startElement(contentHandler, "InUse"); 232 233 _saxPopulationsInUse(usedPopulations); 234 235 _saxDatasourcesInUse(usedPopulations); 236 237 XMLUtils.endElement(contentHandler, "InUse"); 238 } 239 240 private void _saxDatasourcesInUse(Set<UserPopulation> usedPopulations) throws SAXException 241 { 242 Pair<Set<String>, Map<String, Set<String>>> usedDatasources = _getDatasourcesUsedByPopulations(usedPopulations); 243 244 XMLUtils.startElement(contentHandler, "Datasources"); 245 246 for (String datasourceId : usedDatasources.getLeft()) 247 { 248 XMLUtils.createElement(contentHandler, "Datasource", _replaceDefaultIds(datasourceId)); 249 } 250 251 XMLUtils.endElement(contentHandler, "Datasources"); 252 253 XMLUtils.startElement(contentHandler, "Datasources-Model"); 254 255 Map<String, Set<String>> datasourcesPerModel = usedDatasources.getRight(); 256 for (String modelId : datasourcesPerModel.keySet()) 257 { 258 XMLUtils.startElement(contentHandler, modelId); 259 260 for (String parameter : datasourcesPerModel.get(modelId)) 261 { 262 XMLUtils.createElement(contentHandler, parameter); 263 } 264 265 XMLUtils.endElement(contentHandler, modelId); 266 } 267 268 XMLUtils.endElement(contentHandler, "Datasources-Model"); 269 } 270 271 private void _saxPopulationsInUse(Set<UserPopulation> usedPopulations) throws SAXException 272 { 273 XMLUtils.startElement(contentHandler, "UserPopulations"); 274 for (UserPopulation userPopulation : usedPopulations) 275 { 276 XMLUtils.createElement(contentHandler, "UserPopulation", userPopulation.getId()); 277 } 278 XMLUtils.endElement(contentHandler, "UserPopulations"); 279 } 280 281 private String _replaceDefaultIds(String datasourceId) 282 { 283 // Default sources won't be default anymore => change it 284 if (_ldapDataSourceManager.getDefaultDataSourceId().equals(datasourceId)) 285 { 286 return _ldapDataSourceManager.getDefaultDataSourceDefinition().getId(); 287 } 288 else if (_sqlDataSourceManager.getDefaultDataSourceId().equals(datasourceId)) 289 { 290 return _sqlDataSourceManager.getDefaultDataSourceDefinition().getId(); 291 } 292 else 293 { 294 return datasourceId; 295 } 296 } 297 298 private Set<UserPopulation> _getPopulationsUsedBySites() 299 { 300 // Retrieve the sites to build the contexts to search on 301 Collection<String> siteNames = _siteManager.getSiteNames(); 302 303 // We return all the populations linked to at least one site 304 List<String> contexts = new ArrayList<>(); 305 for (String siteName : siteNames) 306 { 307 contexts.add("/sites/" + siteName); 308 contexts.add("/sites-fo/" + siteName); 309 } 310 311 Set<String> populations = _populationContextHelper.getUserPopulationsOnContexts(contexts, false, false); 312 return populations.stream().map(_userPopulationDAO::getUserPopulation).collect(Collectors.toSet()); 313 } 314 315 private Pair<Set<String>, Map<String, Set<String>>> _getDatasourcesUsedByPopulations(Set<UserPopulation> usedPopulations) 316 { 317 Set<String> datasourcesInUse = new HashSet<>(); 318 Map<String, Set<String>> datasourcesPerModel = new HashMap<>(); 319 320 for (UserPopulation userPopulation : usedPopulations) 321 { 322 for (UserDirectory userDirectory : userPopulation.getUserDirectories()) 323 { 324 String userDirectoryModelId = userDirectory.getUserDirectoryModelId(); 325 UserDirectoryModel userDirectoryModel = _userDirectoryFactory.getExtension(userDirectoryModelId); 326 327 Map<String, Object> parameterValues = userDirectory.getParameterValues(); 328 329 Map<String, ? extends ElementDefinition> userDirectoryModelParameters = userDirectoryModel.getParameters(); 330 for (String userDirectoryModelParameterId : userDirectoryModelParameters.keySet()) 331 { 332 ElementDefinition userDirectoryModelParameter = userDirectoryModelParameters.get(userDirectoryModelParameterId); 333 if (ModelItemTypeConstants.DATASOURCE_ELEMENT_TYPE_ID.equals(userDirectoryModelParameter.getType().getId())) 334 { 335 String datasourceId = (String) parameterValues.get(userDirectoryModelParameterId); 336 datasourcesInUse.add(datasourceId); 337 _addDatasourceToModel(userDirectoryModelId, userDirectoryModelParameterId, datasourcesPerModel); 338 } 339 } 340 } 341 342 for (CredentialProvider credentialProvider : userPopulation.getCredentialProviders()) 343 { 344 String credentialProviderModelId = credentialProvider.getCredentialProviderModelId(); 345 CredentialProviderModel credentialProviderModel = _credentialProviderFactory.getExtension(credentialProviderModelId); 346 347 Map<String, Object> parameterValues = credentialProvider.getParameterValues(); 348 349 Map<String, ? extends ElementDefinition> credentialProviderModelParameters = credentialProviderModel.getParameters(); 350 for (String credentialProviderParameterId : credentialProviderModelParameters.keySet()) 351 { 352 ElementDefinition credentialProviderModelParameter = credentialProviderModelParameters.get(credentialProviderParameterId); 353 if (ModelItemTypeConstants.DATASOURCE_ELEMENT_TYPE_ID.equals(credentialProviderModelParameter.getType().getId())) 354 { 355 String datasourceId = (String) parameterValues.get(credentialProviderParameterId); 356 datasourcesInUse.add(datasourceId); 357 _addDatasourceToModel(credentialProviderModelId, credentialProviderParameterId, datasourcesPerModel); 358 } 359 } 360 } 361 } 362 363 return Pair.of(datasourcesInUse, datasourcesPerModel); 364 } 365 366 private void _addDatasourceToModel(String modelId, String datasource, Map<String, Set<String>> datasourcesPerModel) 367 { 368 Set<String> datasources = datasourcesPerModel.get(modelId); 369 if (datasources == null) 370 { 371 datasources = new HashSet<>(); 372 datasourcesPerModel.put(modelId, datasources); 373 } 374 375 datasources.add(datasource); 376 } 377}