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