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