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.plugins.datasourcesexplorer;
017
018import java.sql.Connection;
019import java.sql.DatabaseMetaData;
020import java.sql.ResultSet;
021import java.util.ArrayList;
022import java.util.HashMap;
023import java.util.List;
024import java.util.Map;
025
026import org.apache.avalon.framework.parameters.Parameters;
027import org.apache.avalon.framework.service.ServiceException;
028import org.apache.avalon.framework.service.ServiceManager;
029import org.apache.cocoon.ProcessingException;
030import org.apache.cocoon.acting.ServiceableAction;
031import org.apache.cocoon.environment.ObjectModelHelper;
032import org.apache.cocoon.environment.Redirector;
033import org.apache.cocoon.environment.Request;
034import org.apache.cocoon.environment.SourceResolver;
035import org.apache.commons.lang3.StringUtils;
036
037import org.ametys.core.cocoon.JSonReader;
038import org.ametys.core.datasource.AbstractDataSourceManager.DataSourceDefinition;
039import org.ametys.core.datasource.ConnectionHelper;
040import org.ametys.core.datasource.DataSourceConsumer.TypeOfUse;
041import org.ametys.core.datasource.DataSourceConsumerExtensionPoint;
042import org.ametys.core.datasource.LDAPDataSourceManager;
043import org.ametys.core.datasource.SQLDataSourceManager;
044import org.ametys.plugins.datasourcesexplorer.LDAPConnector.DN;
045
046/**
047 * Generates the list of tables on the given datasource id
048 */
049public class GetDatasources extends ServiceableAction
050{
051    private SQLDataSourceManager _sqlDataSourceManager;
052    private LDAPDataSourceManager _ldapDataSourceManager;
053    private DataSourceConsumerExtensionPoint _dataSourceConsumerEP;
054    private LDAPConnector _ldapConnector;
055
056    @Override
057    public void service(ServiceManager smanager) throws ServiceException
058    {
059        super.service(smanager);
060        
061        _sqlDataSourceManager = (SQLDataSourceManager) smanager.lookup(SQLDataSourceManager.ROLE);
062        _ldapDataSourceManager = (LDAPDataSourceManager) smanager.lookup(LDAPDataSourceManager.ROLE);
063        _ldapConnector = (LDAPConnector) smanager.lookup(LDAPConnector.ROLE);
064        _dataSourceConsumerEP = (DataSourceConsumerExtensionPoint) smanager.lookup(DataSourceConsumerExtensionPoint.ROLE);
065    }
066    
067    public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception
068    {
069        Map<String, Object> results = new HashMap<>();
070        
071        Request request = ObjectModelHelper.getRequest(objectModel);
072        request.setAttribute(JSonReader.OBJECT_TO_READ, results);
073
074        String id = request.getParameter("node");
075        if (StringUtils.isBlank(id))
076        {
077            id = "root";
078        }
079
080        Object children;
081        if ("root".equals(id))
082        {
083            children = _datasources2JSON();
084        }
085        else if (id.startsWith(SQLDataSourceManager.SQL_DATASOURCE_PREFIX))
086        {
087            children = _sqlDatasource2JSON(id);
088        }
089        else
090        {
091            children = _ldapDatasource2JSON(id);
092        }
093        
094        results.put("id", id);
095        results.put("children", children);
096        
097        return EMPTY_MAP;
098    }
099
100    private Object _datasources2JSON()
101    {
102        List<Map<String, Object>> datasources = new ArrayList<>();
103
104        for (DataSourceDefinition dataSourceDefinition : _sqlDataSourceManager.getDataSourceDefinitions(true, true, false).values())
105        {
106            Map<String, Object> datasource = new HashMap<>();
107            datasources.add(datasource);
108            
109            boolean isInUse = TypeOfUse.merge(_dataSourceConsumerEP.isInUse(dataSourceDefinition.getId()), dataSourceDefinition.isDefault() ? _dataSourceConsumerEP.isInUse(_sqlDataSourceManager.getDefaultDataSourceId()) : TypeOfUse.NOT_USED) != TypeOfUse.NOT_USED;
110            
111            datasource.put("id", dataSourceDefinition.getId());
112            datasource.put("nodetype", "datasource");
113            datasource.put("type", "SQL");
114            datasource.put("isDefault", dataSourceDefinition.isDefault());
115            datasource.put("isInUse", isInUse);
116            datasource.put("text", dataSourceDefinition.getName());
117            datasource.put("description", dataSourceDefinition.getDescription());
118            datasource.put("iconCls", "ametysicon-data110");
119            datasource.put("leaf", "false");
120        }
121        
122        for (DataSourceDefinition dataSourceDefinition : _ldapDataSourceManager.getDataSourceDefinitions(true, true, false).values())
123        {
124            Map<String, Object> datasource = new HashMap<>();
125            datasources.add(datasource);
126            
127            boolean isInUse = TypeOfUse.merge(_dataSourceConsumerEP.isInUse(dataSourceDefinition.getId()), dataSourceDefinition.isDefault() ? _dataSourceConsumerEP.isInUse(_ldapDataSourceManager.getDefaultDataSourceId()) : TypeOfUse.NOT_USED) != TypeOfUse.NOT_USED;
128            
129            datasource.put("id", dataSourceDefinition.getId());
130            datasource.put("nodetype", "datasource");
131            datasource.put("type", "LDAP");
132            datasource.put("isDefault", dataSourceDefinition.isDefault());
133            datasource.put("isInUse", isInUse);
134            datasource.put("text", dataSourceDefinition.getName());
135            datasource.put("description", dataSourceDefinition.getDescription());
136            datasource.put("iconCls", "ametysicon-agenda3");
137            datasource.put("leaf", "false");
138        }
139
140        return datasources;
141    }
142
143    private Object _sqlDatasource2JSON(String sqlDatasourceId) throws ProcessingException
144    {
145        List<Map<String, String>> tables = new ArrayList<>();
146        
147        Connection connection = null;
148        ResultSet rs = null;
149        try
150        {
151            connection = ConnectionHelper.getConnection(sqlDatasourceId);
152            
153            String databaseType = ConnectionHelper.getDatabaseType(connection);
154            if (databaseType == null)
155            {
156                throw new IllegalArgumentException("The datasource '" + sqlDatasourceId + "' does not exist");
157            }
158            
159            DatabaseMetaData md = connection.getMetaData();
160            rs = md.getTables(connection.getCatalog(), connection.getSchema(), "%", new String[] {"TABLE", "VIEW"});
161            while (rs.next()) 
162            {
163                Map<String, String> table = new HashMap<>();
164                table.put("id", rs.getString(3));
165                table.put("datasourceId", sqlDatasourceId);
166                table.put("nodetype", "sqltable");
167                table.put("text", rs.getString(3));
168                table.put("iconCls", "ametysicon-tables1");
169                table.put("leaf", "true");
170                tables.add(table);
171            }
172        }
173        catch (Exception e) 
174        {
175            throw new ProcessingException("Cannot list SQL tables of datasource '" + sqlDatasourceId + "'", e);
176        }
177        finally 
178        {
179            ConnectionHelper.cleanup(rs);
180            ConnectionHelper.cleanup(connection);
181        }
182        
183        return tables;
184    }
185    
186    private Object _ldapDatasource2JSON(String ldapDatasourcePath) throws ProcessingException
187    {
188        List<Map<String, String>> nodes = new ArrayList<>();
189
190        String ldapDatasourceId = StringUtils.substringBefore(ldapDatasourcePath, ";");
191        String currentDN = StringUtils.substringAfter(ldapDatasourcePath, ";");
192        
193        for (DN dn : _ldapConnector.getChildren(ldapDatasourceId, currentDN))
194        {
195            Map<String, String> node = new HashMap<>();
196            node.put("id", ldapDatasourceId + ";" + dn.getDN() + (StringUtils.isEmpty(currentDN) ? "" : "," + currentDN));
197            node.put("datasourceId", ldapDatasourceId);
198            node.put("nodetype", "ldapnode");
199            node.put("text", dn.getLabel());
200            node.put("iconCls", "ametysicon-menu");
201            node.put("leaf", dn.hasChild() ? "false" : "true");
202            nodes.add(node);
203        }
204        
205        return nodes;
206    }
207}